聚集索引與非聚集索引

索引能提高速度的原因是找到待搜索數據範圍的開始和結束位置,然後根據頭尾把中間的數據快速的取出來。索引其實是把查詢語句所需要的少量數據添加到索引分頁中,查詢的時候通過訪問少量的索引分頁就可以到可以快速的確定搜索數據範圍的開始和結束位置。

索引存在的目的是在大量數據中找尋少量數據時,提高查詢速度。查詢!查詢!查詢!所以試圖用索引增加IUD(insert\update\delete)操作效率的人就把枕頭墊高點醒一醒。

把一張表放在最前面,因爲真正用的時候,你不會去看一大堆的概念分析,看這張表就夠了。

聚集索引與非聚集索引使用的情況:

 動作描述

使用聚集索引 

 使用非聚集索引

 外鍵列

 應

 應

 主鍵列

 應

 應

 列經常被分組排序(order by)

 應

 應

 返回某範圍內的數據

 應

 不應

 小數目的不同值

 應

 不應

 大數目的不同值

 不應

 應

 頻繁更新的列

 不應 

 應

 頻繁修改索引列

 不應

 應

 一個或極少不同值

 不應

 不應

 

數據庫有一個堆的概念。

堆就是存儲索引頁和數據結點的一個邏輯區。在堆中頁面是沒有順序的,頁中的行也是沒有順序的。

 

聚集索引

聚集索引是索引順序與表中數據的物理存儲順序一致。注意:是索引順序與數據的順序一致,物理順序會因爲聚集索引的建立而把【同一類】數據放在同一個數據節點,這樣子可以方便查找。所以聚集索引的索引指向看起來會非常亂。

因爲表中數據的物理存儲順序只有一個,所以聚集索引在一張表中只有一個。所以聚集索引對於一張表非常寶貴。所以,瞭解聚集索引在什麼情況下使用是非常重要的。

聚集索引使用的一個非常重要的規則是“字段用於範圍查詢”的規則。這個規則還有一個翻譯版——“聚集索引不適合建立在相同值數量特別多或特別少的字段上。”1)若某字段A絕大多數相同,那麼建立索引並不能帶來明顯速度提升(因爲它不能儘可能縮小數據範圍),還會額外佔用空間,說不定還會影響查詢速度。比如字段姓別。2)如果某個字段只有極少數相同的值,完全可以用非聚集索引代替。你可以使用聚集索引,比如我們日常會默認主鍵就是聚集索引。但是這其實是一種浪費。數據庫表中會根據主鍵決定數據是否存儲在同一個數據節點上。所以如果主鍵作爲聚集索引,建起來的索引順序正好與物理順序一致,會把數據按主鍵分在不同的結點裏。對於底層而言會存在非常少的跨頁指針這種消耗。所以相比用主鍵建立非聚集索引,用主鍵建聚集索引的空間消耗會更小。但是,出於聚集索引只能有一個。所以如果你的業務需求有範圍查詢的前提下,你的主鍵正好不是範圍查詢使用到的字段,那麼聚集索引放在範圍查詢的字段上的作用會比放在主鍵上強很多。舉例:有些情況會針對一個自增ID字段建立主鍵,如果這個字段ID如果不涉及到範圍查詢,那麼沒有必要去建立聚集索引。對於sqlserver,會默認把主鍵建一個聚集索引,但是大家在做性能優化的時候,需要關注這個聚集索引真的發揮他的價值。

所以聚集索引更準確的建議建立索引的規則是“用於範圍查詢的字段纔去建立聚集索引”。

聚集索引最好在範圍查詢內是返回整行數據。

又會有人問,如果是索引的順序與物理順序一致,那爲什麼聚集索引只能有一個?請大家要保持一個觀點:沒有一個東西是絕對好或者絕對壞的。有得會也有失。索引是爲了提高查詢效率的。所以對於IUD操作是有影響。因此,如果你一表中有10個聚集索引,我做一個update操作,十個索引都需要做改變。這個消耗是巨大的,那麼跟我們建立索引的目的相悖了。而且如果建了多個聚集索引,那麼以哪個聚集索引爲準來建立物理順序呢?!因此,聚集索引只能有一個。

 

非聚集索引

非聚集索引與聚集索引在概念上的區別我就不說了。非聚集索引與聚集索引實現上最大的不同在於,非聚集索引是利用聚集索引實現數據快速定位——非聚集索引先找到聚集索引裏具體的頁A,再利用頁A找到對應的數據存儲位置。所以非聚集索引我給他起一個外號叫【基於索引的索引】。

非聚集索引對於只輸出某幾列時性能更佳。因爲此時形成了覆蓋索引,索引所存儲的內容就是最終輸出的數據,所以查詢性能更優。

還有一種情況需要用到非聚集索引,就是order by 字段。order by 字段用非聚集索引可以避免執行時進行排序運算。

我個人認爲非聚集索引的索引頁也是根據索引字段排序好的。這才能達到查詢高效的目的。

索引的順序

建立索引的時候,索引的順序非常重要。我們舉例來說明。

有索引(a,b,c)。那麼查詢條件中(a) (a,b) (a,b,c)都會被使用到。注意,查詢條件的順序是不會影響索引的命中。你寫where a=1 and b=2 and c=3和where c=3 and b=2 and  a=1是沒有區別的。

但是,如果你的查詢條件是(a,d)或者是(b,c),就不會命中索引(a,b,c)。

 

如何查看某個sql的執行時間

把中間執行的腳本(代碼第三行)替換成實際的執行腳本即可。

declare @d datetime
set @d=getdate()
select * from table --這裏就是沒有分號
select 執行時間 = datediff(ms,@d,getdate())

索引優化方法

1、查詢時用到索引的地方

對於一個簡單sql查詢語句主要包含:

(1) distinct 【可以用到索引】

(2) where 【可以用到索引】

  • 集合比較, in 和 exsit都可以用到索引。但是not in 或者 not exsit用不到索引。
  • 文本匹配,like,like ‘name%’可以用到索引
  • 避免在where中使用! =,>=,<=,> , <

(3)order by【可以用到索引】

(4) group by【可以用到索引】

(5) 聚集函數【用不到索引

2、 使用聯合索引

因爲一個表只能用一個索引,所以在用到and條件的時候就要考慮聯合索引

3、 使用覆蓋索引

只需要查詢索引表,就不需要再查詢數據表了。(解釋見非聚集索引)

4、 建立短索引(對應varchar類型)

例如有一個CHAR(255)的列,如果在前10個或20個字符內,多數值是惟一的,那麼就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁盤空間和I/O操作。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章