這是數據庫索引相關內容的第五篇
複製代碼
觸發咱們考慮考慮索引是否合適的契機有兩種數據庫
一種是:生產環境中出現查詢慢,咱們急於解決現實遇到的問題;
一種是:在設計實現階段,咱們但願提早發現設計不合理的索引,以避免後續發佈之後纔出現性能問題;
複製代碼
對於 狀況,咱們能夠經過提問來反思如何改進索引。post
1. 是否全部where子句中的全部列都在索引中了?性能
若是沒有,則添加到索引中,將索引變成半寬索引優化
2. 是否將全部涉及的列都加入到索引中了?spa
若是變成半寬索引後,仍是沒有解決到性能問題,那麼下一個選擇就是將查詢中全部涉及的列都加入到索引中,造成寬索引;這樣,優化器的訪問只需訪問索引,避免了表訪問。設計
3. 你須要最佳索引code
若是上述兩種方式,仍未解決性能問題,則要參考《什麼是最好的索引》一文,好好考慮一下索引的設計了索引
例如:SELECT A FROM XXX WHERE B = 1 AND C = 2;而索引是(A, B, C) 按照《索引》中的優化器邏輯,其索引片是空,即其查詢將進行全索引掃描;若是索引超過10w條記錄,那麼查詢將會很慢get
可是按照上述的檢查方式,第一條和第二條其都是知足的,可是該索引在必定的數量級下依然會致使查詢效率慢,那麼就要作第三步,對索引進行從新考慮了。io
在正式運行的系統中,建議擴充索引列,而不是新增新的索引或者更換索引列的順序,和將帶來額外的負擔。
對於 狀況,咱們能夠經過系統的評估來查看索引是否合適。
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》
數據庫索引相關文章之三:《索引》
數據庫索引相關文章之四:《什麼索引算是好的索引》
數據庫索引相關文章之五:《如何發現及替換不合適的索引》
數據庫索引相關文章之六:《索引總結》