2017-08-13 119 views
0

我有這樣定義的表: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) 

拍攝,在兩個已經索引了,爲什麼我把它們放在一起,查詢變得更糟?由於更多的索引,它不應該更快嗎?

+0

類似的問題,但在SQL Server中是:[爲什麼多個WHERE條件慢查詢,而不是加速?](https://stackoverflow.com/q/2162621/4519059);)。 –

回答

2

我不知道「如果文章表增長到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將被淘汰的幫助。

0

導航索引所涉及的工作比表掃描相當快。如果存在均勻分割,是/否索引可能會毫無價值。

如果您只有幾個匹配項,請考慮爲相關行構建另一個表並加入回去,並在處理它們時將其移除。在其他dbs中,您將構建一個條件索引。

0

它「變得很慢」,因爲沒有那麼多的行與taken=0 and over=0。而innodb_buffer_pool_size太小。但是,要小心,這個設置不應該太大才能導致交換。你有多少內存?