1. 程式人生 > >sqlserver的索引創建

sqlserver的索引創建

因此 exist 9.png 最近鄰 命中 索引 ont clust 查看sql

隨著系統數據的增多,一些查詢逐漸變慢,這時候我們可以根據sqlserver的執行計劃,查看sql的開銷,然後根據開銷創建索引。

索引有聚集索引與非聚集索引。

聚集索引:聚集索引在存儲上是按照順序存儲的,就像字典裏的漢字。

非聚集索引:物理存儲不連續,但邏輯上是連續的,因為單獨維護著數據的存儲位置與數據的關系。

首先寫入100000數據

DECLARE @i INT,    
@num int    
SET @i=0   
SET @num=100000    
WHILE @i<=@num    
BEGIN    
 IF NOT EXISTS(SELECT * FROM  dbo.meter_manage WHERE
meter_id=@i) INSERT INTO dbo.meter_manage ( meter_id , meter_no , meter_name ) VALUES ( @i , -- meter_id - int asdasd+CONVERT(VARCHAR(20),@i), -- meter_no - varchar(500) asdsf++CONVERT(VARCHAR
(20),@i) -- meter_name - varchar(500) ); SET @i=@i+1; END go

非聚集索引的創建:

create NONCLUSTERED INDEX index1 ON meter_manage(meter_no)  

效果:

select * from meter_manage where meter_no=asdasd2

創建非聚集索引之前,耗時23毫秒左右

技術分享圖片

創建非聚集索引之後,瞬間完成

技術分享圖片

經常使用多條件語句查詢時,我們可創建復合索引。

select
* from meter_manage where meter_no=asdasd2 and meter_name=asdsf2

未創建非聚集索引,耗時30毫秒:

技術分享圖片

在meter_no字段創建單索引,耗時3毫秒:

create NONCLUSTERED INDEX index1 ON meter_manage(meter_no)  

技術分享圖片

條件查詢位置更換:

select * from meter_manage where meter_name=asdsf2 and  meter_no=asdasd2 

技術分享圖片

查詢速度沒變,同樣3毫秒。

我們同時在另一個字段meter_name上也建立一個非聚集索引:

create NONCLUSTERED INDEX index2 ON meter_manage(meter_name)  

技術分享圖片

發現兩個非聚集索引的時間與一個聚集索引的時間沒有太大變化,查看執行計劃,只命中了index1索引:

技術分享圖片

分析:

我們來想象一下當數據庫有N個索引並且查詢中分別都要用上他們的情況:
查詢優化器(用大白話說就是生成執行計劃的那個東西)需要進行N次主二叉樹查找[這裏主二叉樹的意思是最外層的索引節點],此處的查找流程大概如下:
查出第一條column1主二叉樹等於1的值,然後去第二條column2主二叉樹查出foo的值並且當前行的coumn1必須等於1,最後去column主二叉樹查找bar的值並且column1必須等於1和column2必須等於foo。
如果這樣的流程被查詢優化器執行一遍,就算不死也半條命了,查詢優化器可等不及把以上計劃都執行一遍,貪婪算法(最近鄰居算法)可不允許這種情況的發生,所以當遇到以下語句的時候,數據庫只要用到第一個篩選列的索引(column1),就會直接去進行表掃描了。

select count(1) from table1 where column1 = 1 and column2 = ‘foo‘ and column3 = ‘bar‘

所以與其說是數據庫只支持一條查詢語句只使用一個索引,倒不如說N條獨立索引同時在一條語句使用的消耗比只使用一個索引還要慢。
所以如上條的情況,最佳推薦是使用index(column1,column2,column3) 這種聯合索引,此聯合索引可以把b+tree結構的優勢發揮得淋漓盡致:
一條主二叉樹(column=1),查詢到column=1節點後基於當前節點進行二級二叉樹column2=foo的查詢,在二級二叉樹查詢到column2=foo後,去三級二叉樹column3=bar查找。

結論:兩個單獨索引通常數據庫只能使用其中一個

創建復合索引:

create index idx1 on meter_manage(meter_no,meter_name) 

技術分享圖片

瞬間完成,發現多條件下適合創建復合索引。

條件位置改變一下

select * from meter_manage where meter_name=asdsf2 and  meter_no=asdasd2 

技術分享圖片

同樣瞬間完成。查看執行計劃命中了idx1

技術分享圖片

我們去掉二個條件:

select * from meter_manage where meter_no=asdasd2

技術分享圖片

同樣瞬間完成,也命中了索引 idx1

技術分享圖片

我們去掉第一個條件:

select * from meter_manage where meter_name=asdsf2

技術分享圖片

耗時27毫秒,與不加索引沒什麽區別,查看執行計劃,發現雖然命中了idx1

技術分享圖片

但是類型卻是Index Scan,與之前的Index Seek不同

區別:

[Table Scan] 表掃描(最慢),對表記錄逐行進行檢查

[Clustered Index Scan] 聚集索引掃描(較慢),按聚集索引對記錄逐行進行檢查

[Index Scan] 索引掃描(普通),根據索引濾出部分數據在進行逐行檢查

[Index Seek] 索引查找(較快),根據索引定位記錄所在位置再取出記錄

[Clustered Index Seek] 聚集索引查找(最快),直接根據聚集索引獲取記錄

因此,字段上同時存在聚集索引與非聚集索引,這種情況下只會命中聚集索引,因為聚集索引最快,例如:主鍵上創建非聚集索引

create NONCLUSTERED INDEX index3 ON meter_manage(meter_id)  

技術分享圖片

瞬間完成,執行計劃:

技術分享圖片

sqlserver的索引創建