[英]Why does removing this index in MySQL speed up my query 100x?
我有以下MySQL表(簡體):
CREATE TABLE `track` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(256) NOT NULL,
`is_active` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
KEY `is_active` (`is_active`, `id`)
) ENGINE=MyISAM AUTO_INCREMENT=7495088 DEFAULT CHARSET=utf8
“ is_active”列標記了我想在大多數(但不是全部)查詢中忽略的行。 我有一些查詢會定期從該表中讀取塊。 其中之一看起來像這樣:
SELECT id,title from track where (track.is_active=1 and track.id > 5580702) ORDER BY id ASC LIMIT 10;
該查詢需要一分鍾的時間才能執行。 這是執行計划:
> EXPLAIN SELECT id,title from track where (track.is_active=1 and track.id > 5580702) ORDER BY id ASC LIMIT 10;
+----+-------------+-------+------+----------------+--------+---------+-------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+----------------+--------+---------+-------+---------+-------------+
| 1 | SIMPLE | t | ref | PRIMARY,is_active | is_active | 1 | const | 3747543 | Using where |
+----+-------------+-------+------+----------------+--------+---------+-------+---------+-------------+
現在,如果我告訴MySQL忽略'is_active'索引,查詢將立即發生。
> EXPLAIN SELECT id,title from track IGNORE INDEX(is_active) WHERE (track.is_active=1 AND track.id > 5580702) ORDER BY id ASC LIMIT 10;
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
| 1 | SIMPLE | t | range | PRIMARY | PRIMARY | 4 | NULL | 1597518 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
現在,真正奇怪的是,如果我強制MySQL使用'is_active'索引,查詢將立即再次發生!
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
| 1 | SIMPLE | t | range | is_active |is_active| 5 | NULL | 1866730 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
我只是不了解這種行為。 在“ is_active”索引中,行應按is_active排序,后跟id。 我在查詢中同時使用了'is_active'和'id'列,因此似乎只需要在樹上繞一圈即可找到ID,然后使用這些ID從表中檢索標題。
這是怎么回事?
編輯:關於我在做什么的更多信息:
看來MySQL在如何使用索引方面做出了錯誤的決定。
從該查詢計划中可以看出,它可能使用了PRIMARY索引或is_active索引,並且選擇了is_active以便首先按track.is_active進行縮小。 但是,它僅使用索引的第一列(track.is_active)。 這樣就得到了3747543的結果,然后必須對其進行過濾和排序。
如果選擇了PRIMARY索引,則可以使用該索引將其范圍縮小到1597518行,並且已經按照track.id的順序對其進行了檢索,因此無需進一步排序。 那會更快。
新的消息:
在使用FORCE INDEX的第三種情況下,MySQL使用的是is_active索引,但現在不僅使用第一列,還使用了兩列(請參閱key_len)。 因此,它現在可以通過is_active進行縮小,並使用相同的索引按id進行排序和過濾,並且由於is_active是單個常量,因此第二列滿足ORDER BY(即,來自索引的單個分支的行已經排序)。 這似乎比使用PRIMARY更好,甚至可能是您最初打算的,對吧?
我不知道為什么沒有FORCE INDEX時不使用該索引的兩列,除非查詢之間以微妙的方式發生了變化。 如果不是的話,我會把它歸咎於MySQL做出錯誤的決定。
我認為加速是由於您的where子句。 我假設它只是在整個大型表中檢索行的一小部分。 在較小的子集上對is_active的檢索數據進行表掃描比通過大型索引文件進行過濾要快。 遍歷單列索引比遍歷組合索引快得多。
您可以嘗試的幾件事:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.