Mysql
為什麼這個 UPDATE 查詢不使用索引?
我有一個查詢:
EXPLAIN UPDATE myTable SET col2 = 'foo' WHERE col1 = 'bar'; +----+-------------+-------------+------------+-------+-----------------------+---------+---------+------+--------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------------+------------+-------+-----------------------+---------+---------+------+--------+----------+-------------+ | 1 | UPDATE | myTable | NULL | index | myTable_ind_indx1 | PRIMARY | 4 | NULL | 890860 | 100.00 | Using where | +----+-------------+-------------+------------+-------+-----------------------+---------+---------+------+--------+----------+-------------+
它使用
PRIMARY
key 而不是使用正確的 indexmyTable_ind_indx1
。這是表創建語句的相關部分:CREATE TABLE `myTable` ( `id` int NOT NULL, ... `col1` varchar(64) DEFAULT NULL, ... PRIMARY KEY (`id`), KEY `myTable_ind_indx1` (`col1`,`col3`), ... ) ENGINE=InnoDB DEFAULT CHARSET=latin1
所以它正在執行全表掃描,而不是使用正確的索引。起初我認為這是因為查詢規劃器估計行數約為 900k,總行數約為 1M,但如果我計算與 WHERE 子句匹配的行數,它實際上是 ~250k,而且甚至添加了
USE INDEX
準確的結果相同的計劃。將查詢更改為SELECT
使用正確索引的結果。這是在 MySQL 8.0.19 上。關於我可以做些什麼來改善事情的任何想法?
如果條件
col1 = 'bar'
匹配 1M 中的 250k 行,即表的25%,這意味著更新將修改表的幾乎所有頁面,因為幾乎每個頁面都會包含至少一個匹配條件的行(除非之間有直接聯繫但是優化id
器col1
無論如何都不知道)。而且當它必須重寫幾乎整個表時,沒有辦法使用索引隨機跳過比只進行全表掃描更好。優化器正在選擇正確的計劃。
id
如果這些行實際上聚集在表的一部分中(和之間存在一些相關性),那麼您可以通過將範圍添加到子句col1
來告訴優化器。但是沒有它,全表掃描只是最快的方法。id``WHERE
對於 select 它可能會有所不同,因為它不必將內容寫入磁碟,它可能會使用不同的 seq/rand 訪問*“價格”*並更多地利用記憶體。因此,沒有類似的計劃
SELECT
並且UPDATE
可能是出乎意料但有效的。