資料庫查詢的關鍵 – Index 索引
索引的建立會直接影響查詢的效能與資料庫整體的運作
索引就像是書本後面書目索引一般,
按照字母排列的關鍵字,或是按照特定類別排列的順序
目的就是讓我們可以快速的找到我們想要的資訊,
而不用一頁一頁或是每個章節循序的搜尋 (Table Scan)
索引可以避免不必要的 Table Scan 讀取,
也是最有效可以避免 Disk I/O 的方法之一
Index 建立過程
在還沒有建立 Index 的時候,所有的資料是沒有經過排序過的
這時候的 Table 會以 Heap Table 的方式提供給 SQL server 存取,
SQL Server 對於沒有排序過的資料就必須要一筆一筆的讀取搜尋,
這樣的讀取Random Disk I/O ,因此很耗費讀取的時間
舉例來說,下列資料,SQL server 每次存取的最小單位為每個 Page 8K
假設每個 page 可以存放三個數字,
要找到 15 ,因為資料沒有經過排序,因此所有的page 都要讀過,讀到最後一個Page,
共9次,才能夠確認15是不是有重複出現或是在每一個 Page 中會出現
要找到 4,也是一樣,需要讀過所有的 Page 共9次
這樣的方法是不是很耗時呢?
Clustered Index
當建立起 Clustered Index 完之後,該 Table 的資料就會進行排序
(註:每一個 Table 僅能有一個 Clustered index)
排序之後,
如果要讀取5,就只需要讀取兩次,第二個 Page 就可以讀取到5
如果要讀取 10,只要讀取四次,第四個Page 就可以讀取到10
但是如果要讀取25,還是一樣要讀取9次
對於數字越大的,讀取次數與時間也就越長,有沒有更有效率的方法呢?
Balance Tree
為了解決排序後資料讀取效率的問題,除了 Table 排序之外,
SQL Server 內部會建立起 Balance Tree. 的樹狀資料結構
Non-Leaf node 例如 Root/Branch node 都是因為索引方便所建立出來的節點
Leaf Node 為實際存放資料的節點,每個節點都是排序過的資料
Branch Node 存放的為 Leaf Node 中每個節點的最小值
就這個Balance Tree 來說,任何數字的搜尋,只要經過三次的讀取即可找到資料
例如
要找到5 ,只需經過三次讀取,Root —> Branch node ( 1 4 7) —> 5
要找到 25,只需經過三次讀取,Root —> Branch node ( 19 22 26) —> 25
如果到 Leaf node 還沒有找到所需的資料,該搜尋就會停止,
避免進入無窮回圈的樹狀搜尋。
Non-Clustered index 的取捨
從上面的例子我們知道,
建立索引可以讓 SQL Server 建立出一個 Balance Tree讓讀取更有效率
那麼我們是不是可以多建立一些索引或是把所有的欄位都建立起索引呢?
建立過多索引會間接造成資料更新時所導致的 overhead
想像一個已經建立起 Balance ,當有資料要更新、新增、修改、刪除時,
該Balance 就必須要重新整理,
當設計 index 的時候必須要考量
現有資料庫運作整體的效能提升與潛在index 所造成的維運成本
可以運用SQL Server 所提供的工具例如:Extended Events或是DMV
- sys.dm_db_index_operational_stats
- sys.dm_db_index_usage_stats.
來觀察該Index 的使用效率與相關統計資訊
- sys.dm_db_index_operational_stats 提供 index 使用時發生的 logical/physical reads I/O 與locks 等的狀態。
- sys.dm_db_index_usage_stats提供index 使用的統計資訊,例如 Index Seek/Scan 的次數等,或是該index 根本沒有就沒有被讀取過。
總結
這篇文章主要說明 index 的使用、運作原理與取捨的考量
想像自己要寫一本書,如何設計一個好的索引目錄讓讀者可以快速的找到所需的資料,
例如一本電腦書,索引類別可以是 Top 10 查詢關鍵字、網路類、記憶體類、資訊安全類等
越多的索引會造成日後編輯上的困難,章節的修改,這些索引都要跟著修改
適當的索引會幫助讀者依照他們想要的內容找到相對應的資訊
索引的使用狀況,資料庫提供DMV 可以供查詢,讓你知道該索引被使用的狀況,
經常被讀取 or 從來都沒有被用到過? 會不會產生 Locks 等,
這些資訊有助於我們做進一步效能調教的分析