MySQL多重索引条件变慢?
问题描述:
我有这样定义的表:MySQL多重索引条件变慢?
article | CREATE TABLE `article` (
`id` varchar(64) NOT NULL,
`type` varchar(16) DEFAULT NULL,
`title` varchar(1024) DEFAULT NULL,
`source` varchar(64) DEFAULT NULL,
`over` tinyint(1) DEFAULT NULL,
`taken` tinyint(1) DEFAULT NULL,
`released_at` varchar(32) DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_article_over` (`over`),
KEY `idx_article_created_at` (`created_at`),
KEY `idx_article_type` (`type`),
KEY `idx_article_taken` (`taken`),
KEY `idx_article_updated_at` (`updated_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
mysql> select count(1) from article;
+----------+
| count(1) |
+----------+
| 649773 |
+----------+
1 row in set (0.61 sec)
当我做一个查询:
SELECT * FROM `article` where taken=0 ORDER BY updated_at asc limit 10;
或
SELECT * FROM `article` where over=0 ORDER BY updated_at asc limit 10;
他们都是非常快的。
然而,当我用这个,它变得非常缓慢:
SELECT * FROM `article` where taken=0 and over=0 ORDER BY updated_at asc limit 10;
这需要4.94s。
如果文章表增长到2000万行,则需要更长的时间。
这里是2000万行的解释:
mysql> explain SELECT * FROM `article` where taken=0 and processed=0 ORDER BY updated_at asc limit 10;
+----+-------------+-----------+------------+-------------+---------------------------------------------+---------------------------------------------+---------+------+---------+----------+-------------------------------------------------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------------+---------------------------------------------+---------------------------------------------+---------+------+---------+----------+-------------------------------------------------------------------------------------------+
| 1 | SIMPLE | article | NULL | index_merge | idx_article_processed,idx_article_taken | idx_article_processed,idx_article_taken | 2,2 | NULL | 6234059 | 100.00 | Using intersect(idx_article_processed,idx_article_taken); Using where; Using filesort |
+----+-------------+-----------+------------+-------------+---------------------------------------------+---------------------------------------------+---------+------+---------+----------+-------------------------------------------------------------------------------------------+
mysql> SELECT * FROM `judgement` where taken=0 and processed=0 ORDER BY updated_at asc limit 10;
+--------------------------------------+----------+-----------+---------------------------------------------------------------------------
| id | type | title | source| processed | released_at | created_at | updated_at | taken |
+--------------------------------------+----------+-----------+---------------------------------------------------------------------------
10 rows in set (9 min 15.97 sec)
拍摄,在两个已经索引了,为什么我把它们放在一起,查询变得更糟?由于更多的索引,它不应该更快吗?
答
我不知道“如果文章表增长到2000万行,为什么它会变慢”这个问题的确切答案。
您的查询做了两个操作:
- index_merge - 使用相交(idx_article_processed,idx_article_taken)
- 使用的filesort
我只能猜测,在表中的MySql高达2000万行可以做这两个操作都在内存中,但高于这个限制,这些操作之一(或者可能是两者)不能放入内存缓冲区,并且MySql必须使用磁盘上的文件,这会慢得多。
您可以增加内存缓冲区tweeking一些MySQL的参数或创建竭诚为您查询的索引:
对于此查询:
SELECT * FROM `article` where taken=0 ORDER BY updated_at asc limit 10;
创建这个索引:
CREATE my_new_index ON article(taken, updated_at)
对于该查询:
SELECT * FROM `article`
where taken=0 and over=0
ORDER BY updated_at asc limit 10;
创建这个索引:
CREATE my_new_index1 ON article(taken, over, updated_at)
有了这些新的指标都和文件排序操作megre将被淘汰的帮助。
答
导航索引所涉及的工作比表扫描相当快。如果存在均匀分割,是/否索引可能会毫无价值。
如果您只有几个匹配项,请考虑为相关行构建另一个表并加入回去,并在处理它们时将其移除。在其他dbs中,您将构建一个条件索引。
答
它“变得很慢”,因为没有那么多的行与taken=0 and over=0
。而innodb_buffer_pool_size
太小。但是,要小心,这个设置不应该太大才能导致交换。你有多少内存?
类似的问题,但在SQL Server中是:[为什么多个WHERE条件慢查询,而不是加速?](https://stackoverflow.com/q/2162621/4519059);)。 –