這是資料庫索引相關内容的第五篇
複制代碼
發現不合适的索引
觸發我們考慮考慮索引是否合适的契機有兩種
一種是:生産環境中出現查詢慢,我們急于解決現實遇到的問題;
一種是:在設計實作階段,我們希望提前發現設計不合理的索引,以免後續釋出以後才出現性能問題;
複制代碼
對于
情況,我們可以通過提問來反思如何改進索引。
1. 是否所有where子句中的所有列都在索引中了?
如果沒有,則添加到索引中,将索引變成半寬索引
2. 是否将所有涉及的列都加入到索引中了?
如果變成半寬索引後,還是沒有解決到性能問題,那麼下一個選擇就是将查詢中所有涉及的列都加入到索引中,形成寬索引;這樣,優化器的通路隻需通路索引,避免了表通路。
3. 你需要最佳索引
如果上述兩種方式,仍未解決性能問題,則要參考《什麼是最好的索引》一文,好好考慮一下索引的設計了
例如:SELECT A FROM XXX WHERE B = 1 AND C = 2;而索引是(A, B, C) 按照《索引》中的優化器邏輯,其索引片是空,即其查詢将進行全索引掃描;如果索引超過10w條記錄,那麼查詢将會很慢
但是按照上述的檢查方式,第一條和第二條其都是滿足的,但是該索引在一定的數量級下依然會導緻查詢效率慢,那麼就要做第三步,對索引進行重新考慮了。
在正式運作的系統中,建議擴充索引列,而不是新增新的索引或者更換索引列的順序,和将帶來額外的負擔。
對于
情況,我們可以通過系統的評估來檢視索引是否合适。
1. 統計本地相應時間
直接先上結論:
本地響應時間(LRT) = 随機通路的數量(TR) * 10ms + 順序通路數量(TS) * 0.01ms + 有效FETCH數量(F) * 0.1ms
什麼是随機通路:就是一次磁盤IO的時間,約為10ms
什麼是順序通路:一頁包含n行,每行的時間約為0.01ms;
再詳細一點:
DBMS讀取一個索引或一個表行的成本,即為一次通路;
DBMS掃描索引或表的一個片段,其中第一行的讀取即為一次随機通路;
對于後續行的讀取,每行都是一次順序通路;
打個比方:
對于去超市買10個罐頭:
随機通路就好比在超市找到罐頭的貨架的時間,就是10ms
順序通路就好比已經找到罐頭的貨架了,隻要一個個把罐頭拿下來,每個罐頭的時間就是0.01ms
好了,知道了随機通路和順序通路,接下來我們知道如何确定随機通路和順序通路的次數
索引通路次數
可以将索引當成一張表,其行數與其包含的表的行數相同,且按照索引鍵值排列
表通路次數
我們假設一次全表掃描将需要一次随機通路和N-1次順序通路
2.舉例:
主鍵索引:select CNAME, CNO, CDESC from table1 where CNO = 221
其中CNO為主鍵;
索引存儲如下:
111,
112,
113
...
221,
222
那麼優化器是如何檢索的?
i. 根據CNO=221,進行一次随機通路,取到221這條索引
ii. 根據221這條索引指向的磁盤位置,通過一次随機通路,找到資料塊,得到CNAME,CDESC
那麼LRT是多少?
很好計算: 兩次随機通路 + 1次FETCH = 2 * 10ms + 0.1ms 約等于 20ms
select CNO, CNAME, CDESC from table1 where CTYPE = 1 and CNAME = 'ZHANG' order by CDESC
假設索引是(CTYPE, CNAME, CDESC) 假設CTYPE =1 和CNAME='ZHANG'能從10w的索引中過濾出1000條
1000條索引如下:
1,'ZHANG', 1
1,'ZHANG', 2
....
1,'ZHANG', 1000
那麼LRT是多少?
首先,一次随機通路索引的時間,定位到索引1000條的第一行
其次, 1000次順序通路索引的時間
然後,因CNO不在索引中,是以還需要通過索引進行磁盤查找;
因為是聚簇索引,是以表的順序和索引的順序是一緻的,通路表的時間和索引是一樣的,即一次随機通路表的時間,和1000次順序通路的時間(999不好計算,我們都約等于1000)
LRT= 1次索引随機通路 + 1000次索引順序通路 + 1次表随機通路 + 1000次表順序通路 + 1000次FETCH
= 10ms + 1000 * 0.01ms + 10ms + 1000 * 0.01ms + 1000 * 0.1ms
= 140ms
同2.2 ,如果同樣是該查詢語句,但是索引變成非聚簇索引會怎麼樣?
很顯然,表的存儲會發生變化,不再是跟索引的順序一緻,并且不是連續存儲了;
是以,
LRT = 1次索引随機通路 + 1000次索引順序通路 + 1000次表随機通路 + 1000次FETCH
= 10ms + 1000 * 0.01ms + 1000 * 10ms + 1000 * 0.1ms
= 10s(約等于)
你看,同樣的1000條索引,查詢速度和2.2相差這麼多!
這個索引該如何優化呢,很顯然,如果它不是聚簇索引,就要将CNO納入到索引中來,避免表的随機通路;将所有的通路都回到索引内部
很顯然,這就是《什麼索引是好的索引》中介紹的所謂的好的索引,知識都是相輔相成的。
使用了該更改後的索引,其LRT會變成多少?
LRT = 10ms + 1000 * 0.01ms + 1000 * 0.1ms = 120ms
速度提升了100倍!
好了,本文重點介紹了如何在實際生産環境中和設計過程中發現問題及優化索引,隻要掌握原則,了解思路,剩下的就是運用了。
其他相關章節
複制代碼
資料庫索引相關文章之一:《B樹,一點都不神秘》
資料庫索引相關文章之二:《B樹很簡單,插入so easy》
資料庫索引相關文章之三:《索引》
資料庫索引相關文章之四:《什麼索引算是好的索引》
資料庫索引相關文章之五:《如何發現及替換不合适的索引》
資料庫索引相關文章之六:《索引總結》