有時看起來相似的查詢會有大不相同的執(zhí)行計劃。我們通過修改人口條件已經(jīng)看到:在例子8中,多于5億 和 多于5百萬會導(dǎo)致索引選擇的不同。
這在生產(chǎn)環(huán)境中經(jīng)常發(fā)生,查詢的一部分是從用戶輸入中產(chǎn)生的:
- 在幾個月的數(shù)據(jù)中查詢?nèi)掌诜秶白蛱斓浆F(xiàn)在”很可能可以用到日期列的索引。而查詢“去年到現(xiàn)在”就不會。
-
WHERE is_deleted=1能夠過濾掉許多記錄,而且很適合用于索引。而相似的WHERE is_deleted=0可能就無法用到索引。
這是合乎預(yù)期的,是已有的上下文環(huán)境(元數(shù)據(jù)和統(tǒng)計信息)造成的結(jié)果。下面的表格展示了隨著“人口”和“大洲”的查詢條件改變,查詢代價的變化。
| p>5百萬 c=亞洲 |
p>5百萬 c=南極洲 |
p>5千萬 c=亞洲 |
p>5千萬 c=南極洲 |
p>5億 c=亞洲 |
p>5億 c=南極洲 |
|
|---|---|---|---|---|---|---|
| p | 152.21 | 152.21 | 34.61 | 34.61 | 3.81 | 3.81 |
| c | 28.20 | 6.00 | 28.20 | 6.00 | 28.20 | 6.00 |
| c,p | 24.83 | 2.41 | 16.41 | 2.41 | 3.81 | 2.41 |
| p,c | 152.21 | 152.21 | 34.61 | 34.61 | 3.81 | 3.81 |
| 全表掃描 | 53.80 | 53.80 | 53.80 | 53.80 | 53.80 | 53.80 |
- 全表掃描有相對固定的查詢代價,因為它只是查看表里的每一行。
- 使用 p 或 c 索引的查詢代價會隨著查詢值的過濾能力而改變(南極洲的國家較少;人口很多的國家較少)。
- 復(fù)合索引(c,p)在減少查詢代價上相對更有效。
- 使用的數(shù)據(jù)集中,南極洲有 4 個人口為 0 的國家。復(fù)合索引(c,p)在南極洲的查詢中展現(xiàn)了極低的的查詢代價,因為只有 0 條結(jié)果。
這些信息也可以通過可視化展示。注意在大洲上的全表掃描和索引訪問都有固定的代價,而當人口條件選擇性不高時,復(fù)合索引(c,p)和索引c的代價相同。
如果復(fù)合索引不是非常有效,你會發(fā)現(xiàn)和使用單列索引的結(jié)果非常相似。最后,因為人口多于 3 億的國家都在亞洲,沒有哪一列的選擇性比人口更好了。

下方的信息圖源于強制使用人口索引,并設(shè)置人口查詢值從1百萬到5億,取100次執(zhí)行的中位數(shù)。執(zhí)行的時間是從performance_schema.events_statements_history_long中取出并轉(zhuǎn)為微秒(μs)的。有一些執(zhí)行時間的數(shù)據(jù)點聚集起來了,我認為是因為數(shù)據(jù)集比較小,并且有少量只有很少人口的國家,這些數(shù)據(jù)可以從同一個頁訪問到。

譯自:
Transient Plans - The Unofficial MySQL 8.0 Optimizer Guide