我們今天來介紹下 MySQL 8.0 引入的新特性:倒序索引。
MySQL長期以來對索引的建立只允許正向asc存儲,就算建立了desc,也是忽略掉。
比如對於以下的查詢,無法發揮索引的最佳性能。
查詢一:
select * from tb1 where f1 = ... order by id desc;
查詢二:
select * from tb1 where f1 = ... order by f1 asc , f2 desc;
那對於上面的查詢,尤其是數據量和並發到一定峰值的時候,則對OS的資源消耗非常大。一般這樣的SQL在查詢計划里面會出現using filesort等狀態
比如針對下面的表t1,針對字段rank1有兩個索引,一個是正序的,一個是反序的。不過在MySQL 8.0 之前的版本都是按照正序來存儲
按照rank1 正向排序的執行計划,
按照rank1 反向排序的執行計划,
從執行計划來看,反向比正向除了extra里多了Using temporary; Using filesort這兩個,其他的一模一樣。這兩個就代表中間用到了臨時表和排序,一般來說,凡是執行計划里用到了這兩個的,性能幾乎都不咋地。除非我這個臨時表不太大,而用於排序的buffer也足夠大,那性能也不至於太差。那這兩個選項到底對性能有多大影響呢?
我們分別執行這兩個查詢,並且查看MySQL的session級的status就大概能看出些許不同。
通過以上兩張圖,我們發現反向的比正向的多了很多個計數,比如通過掃描的記錄數增加了10倍,而且還伴有10倍的臨時表的讀和寫記錄數。那這個開銷是非常巨大的。那以上的查詢是在MySQL 5.7 上運行的。
MySQL 8.0 給我們帶來了倒序索引(Descending Indexes),也就是說反向存儲的索引。 這里不要跟搜索引擎中的倒排索引混淆了,MySQL這里只是反向排序存儲而已。不過這個倒序存儲已經解決了很大的問題。我們再看下之前在MySQL 5.7 上運行的例子。
我們把數據導入到MySQL 8.0,
再把原來的索引變為倒序索引,
再次看下第二個SQL的查詢計划,
很顯然,用到了這個倒序索引 idx_rank1_desc,而這里的臨時表等的信息消失了
當然了,這里的組合比較多,比如我這張表的字段rank1,rank2兩個可以任意組合
組合一:
(rank1 asc,rank2 asc);
組合二:
(rank1 desc,rank2 desc);
組合三:
(rank1 asc,rank2 desc);
組合四:
(rank1 desc,rank2 asc);
我把這幾個加上,適合的查詢比如:
查詢一:
Select * from t1 where rank1 = 11 order by rank2;
查詢二:
Select * from t1 where 1 order by rank1,rank2;
查詢三:
Select * from t1 where 1 order by rank1 desc,rank2;
。。。。。
等等,這里就不一一示范了!