sqlserver的索引創建
隨著系統數據的增多,一些查詢逐漸變慢,這時候我們可以根據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 WHEREmeter_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的索引創建