主要參考了博文:宋沄劍 -理解SQL SERVER中的邏輯讀,預讀和物理讀 和 宋沄劍 - T-SQL查詢進階--理解SQL Server中索引的概念,原理以及其他,以下內容為對其博文的讀書筆記。 1. 資料庫的數據存儲形式 在談到幾種不同的讀取方式之前,首先要理解SQL SERVER數據存儲的方式...
主要參考了博文:宋沄劍 -理解SQL SERVER中的邏輯讀,預讀和物理讀 和 宋沄劍 - T-SQL查詢進階--理解SQL Server中索引的概念,原理以及其他,以下內容為對其博文的讀書筆記。
1. 資料庫的數據存儲形式
在談到幾種不同的讀取方式之前,首先要理解SQL SERVER數據存儲的方式.SQL SERVER存儲的最小單位為頁(Page).每一頁大小為8k,SQL SERVER對於頁的讀取是原子性,要麼讀完一頁,要麼完全不讀,不會有中間狀態。而頁之間的數據組織結構為B樹。所以SQL SERVER對於邏輯讀,預讀,和物理讀的單位是頁.
原子性,指不可再分。頁是資料庫讀取數據的最小單位,所以上圖中那種顯示,讀取了多少次,都是指的是讀取了多少頁數據。
2. SQL SERVER數據讀取順序
當SQL Server執行一個查詢語句時,SQL Serer會開始第一步,生成查詢計劃,同時用估計的數據去磁碟讀取數據(預讀),這兩個第一步是並行的。SQL Server通過這種方式來提高查詢性能。
查詢計劃生成好了以後去緩存讀取數據,當發現緩存缺少所需要的數據後讓緩存再次去讀硬碟(物理讀),然後從緩存中取出所有數據(邏輯讀)。
也即,一般生產環境中,開啟io查詢後,可能不太容易看到物理讀取的操作,因為執行過1次後系統會將其緩存下來,所以這種情況下,物理讀的優化不用考慮,只要想辦法讓邏輯讀的次數儘可能少就可以大幅度提高查詢性能了。
3. 索引的原理
在資料庫檢索來說,對於磁碟IO掃描是最消耗時間的.因為磁碟掃描涉及很多物理特性,這些是相當消耗時間的。所以B樹設計的初衷是為了減少對於磁碟的掃描次數。如果一個表或索引沒有使用B樹(對於沒有聚集索引的表是使用堆heap存儲),那麼查找一個數據,需要在整個表包含的資料庫頁中全盤掃描。這無疑會大大加重IO負擔.而在SQL SERVER中使用B樹進行存儲,則僅僅需要將B樹的根節點存入記憶體,經過幾次查找後就可以找到存放所需數據的被葉子節點包含的頁!進而避免的全盤掃描從而提高了性能.
也即,使用索引以後,數據的存儲會由無序的堆變成b樹,完成從無序到有序的轉變。
4. 聚集索引
為了提高某個屬性(或屬性組)的查詢速度,把這個或這些屬性(稱為聚集碼)上具有相同值的元組集中存放在連續的物理塊稱為聚集。
在SQL SERVER中,聚集的作用就是將某一列(或是多列)的物理順序改變為和邏輯順序相一致,比如,我從adventureworks資料庫的employee中抽取5條數據:
當我在ContactID上建立聚集索引時,再次查詢:
所以,核心是:聚集索引改變的是其所在表的物理存儲順序,所以每個表只能有一個聚集索引.
由於有主鍵的表,系統會預設將其建成聚集索引,所以個人感覺,如果主鍵是用自增id做的話,不如不要將其設為主鍵,因為自增id一般在查詢中不會太經常使用,反而是【時間】、【日期】等欄位在查詢時很方便縮小數據集的範圍,因此將之設定成聚集索引,個人覺得應該會對查詢速度有明顯提高。
5. 非聚合索引
一個簡單的非聚集索引概念如下:
可以看到,非聚集索引需要額外的空間進行存儲,按照被索引列進行聚集索引,併在B樹的葉子節點包含指向非聚集索引所在表的指針.
如果用目錄來比喻索引的話,個人感覺,應該是醬紫的:
聚集索引:
就是標準的目錄樣式: 頁碼(聚集索引列) || 頁碼對應的內容
非聚集索引:
是一種嵌套的目錄,類似: 頁碼(非聚集索引列) || 頁碼對應的聚集索引列
也即,非聚集索引查詢時,應該是先通過非聚集索引查到對應的聚集索引列,而後再通過聚集索引查詢到目標內容。
顯然,非聚集索引多了一些操作,因此查詢速度上必然比聚集索引要慢,但好處在於,聚集索引只能有一個,可非聚集索引可以有多個,因此給了更多的查詢方式。