淺談數據庫索引的結構設計與優化
一. 了解數據庫索引的必要性
對於稍微數據量大一點的表,如果不適用索引,那么性能效率都會很低;如果繞開了索引,直接進行分區分表,數據庫集群讀寫分離來解決性能問題的話,那么未免也太小題大做了。
對於大多數中小型系統,索引能夠幫你解決90%的性能問題,所以索引是解決關系型數據庫非常有利的武器。
二. 表和索引結構
1.索引頁和表頁
表和索引都是存在頁中。頁的大小一般是4KB.頁的大小僅僅決定了一個頁能存儲多少個索引行,表行。
2.索引行
索引行是很有用的一個概念對於訪問路徑的時候。索引行的概念可以通過下圖來了解:
每一個頁上包含了很多索引行,每個索引行里存儲着索引條目和指向下一層的頁,這種數據結構為B-tree結構。
3.緩沖池和磁盤I/O
我們可以使用內存的緩沖池來減小到磁盤的訪問。這一策略對sql性能表現至關重要。下圖展示了磁盤讀取到緩沖區的巨大成本:
當我們需要某一頁的一行數據時,和需要這一頁的數據時,所花費的時間是相等的。可以通過執行:show global status like 'innodb%read%';來判斷緩存命中的情況,具體的參數可以自行在網上查找:
可以算出來緩存命中率為=260850/(64+260850+1927)=99.24%,是很高的命中率了。
4.硬件特性
硬盤磁盤的圖可以用下圖簡單表示:
我們的數據庫表里的數據就保存在磁盤上,如果要讀取數據,就要磚頭磁盤,用磁頭和磁盤的磁力來改變狀態,來讀取數據,所以,我們應該盡量少的轉動磁盤,來優化數據庫性能。
三.SQL處理過程
我們現在先討論基礎的處理過程,先來談談處理過程的一些基本概念。
1.關鍵字(謂詞)
where子句由一個或者多個謂詞組成,比如說:
那么這個就有一個組合謂詞,組合謂詞是索引設計的主要入手點。
2.過濾因子
過濾因子是描述謂詞的選擇性,它主要依賴於列值的分布情況。它是一個計算值,公式為:
用來計算謂詞結果集的返回大小估算。
3.物化結果集
是執行數據庫訪問來構建結果集。最好的情況下,是從數據庫緩沖池返回一條記錄,最壞的情況就是訪問大量的磁盤讀取數據。
物化結果集有2種方式:
1.一次FETCH物化返回一條數據
2.提前物化
四.為SELECT語句創建理想索引
1.三星索引
三星索引是指一條sql所能達到索引的最優設計。
第一顆星:
如果與一個查詢相關的索引行是相鄰的,那么這個索引就為第一顆星。
第二顆星:
如果索引行的順序與查詢語句一致,則為第二顆星。
第三顆星:
查詢的數據為索引的信息,不需要額外的磁盤隨機讀。這一顆星能大大改善性能。
假設有一條sql語句如下所示:
如果要滿足一星索引:索引的順序可以是LNAME,CITY或者CITY,LNAME
如果要滿足第二星索引:FNAME加在LNAME,CITY或者CITY,LNAME后面
如果要滿足第三索引:CNO也要在索引里面
那么組合起來得三星索引就是:LNAME,CITY,FNAME,CNO或者CITY,LNAME,FNAME,CNO
五.前瞻性索引
1.發現不合適的索引
有兩種基本的方法來發現不合適的索引:
1.基本問題法(BQ)
2.快速上線評估法(QUBE)
在這里我僅僅討論一下快速上線評估法(QUBE)
2.快速上線評估法(QUBE)
QUBE是悲觀上限,它的目的是在早期發現程序設計的缺陷,並且及時更改。QUBE忽略了排隊時間,鎖競爭時間等,把問題單一化來評估sql的性能問題。
下圖就是QUBE計算評估sql時間公式:
可以發現,TR和TS存在巨大的時間差距,隨機訪問會消耗大量的時間,那么來說說隨機和順序訪問。
隨機訪問:
先說一說磁盤讀和訪問的區別。讀是讀取一頁的信息,訪問時訪問一行的信息。所以單次隨機訪問的時間與一次磁盤隨機讀取的時間相同,都是10ms。
順序訪問:
一次順序讀是指物理上讀取連續的下一行,這一行要么在同一頁中,要么在下一頁中,估算出來時間是0.01ms。
FETCH:
是FETCH調用次數來確定被接收行的數量。F的時間數量級要比TS大一級,但是要比TR小2級。
下面給出一個簡單的事例來說明QUBE計算方法:
那么可以根據上面的公式得到:
QUBE算法其實可以多結合自己的項目事例來計算判斷一下,因為這個公式是很多年前的了,現在磁盤讀寫能力肯定有了顯著提升,但是判斷sql性能的方式是一致的。