我們都知道建立適當的索引能夠提高查詢(xún)速度,優(yōu)化查詢(xún)。先說(shuō)明一下,無(wú)論是聚集索引還是非聚集索引都是B樹(shù)結構。
CREATE TABLE MyTableKeyExample{ Column1 int IDENTITY KEY NONCLUSTERED, Column2 int }
索引(index)是除了表之外的另一個(gè)重要的、用戶(hù)定義的存儲在數據庫里的數據結構。當根據索引碼的值搜索數據時(shí),索引提供了對數據的快速訪(fǎng)問(wèn)。事實(shí)上,沒(méi)有索引數據庫也能夠根據SELECT語(yǔ)句通過(guò)表掃描成功地檢索到結果,但是隨著(zhù)表變得越來(lái)越大,使用“適當”的索引的效果就越來(lái)越明顯。但如果使用索引時(shí)不認真考慮其實(shí)現過(guò)程,索引反而有可能會(huì )降低數據庫的工作性能。創(chuàng )建主鍵時(shí)會(huì )自動(dòng)創(chuàng )建聚集索引,除非當前表中已經(jīng)含有了聚集索引或是創(chuàng )建主鍵時(shí)指定了NONCLUSTERED關(guān)鍵字。
聚集索引、非聚集索引、非聚集唯一索引:
SqlServer提供了兩種索引:聚集索引和非聚集索引。聚集的作用就是將某一列(或是多列)的物理順序改變?yōu)楹瓦壿嬳樞蛳嘁恢隆?/p>
聚集索引(CLUSTERED)與非聚集索引(NONCLUSTERED)的區別:
其實(shí),我們的漢語(yǔ)字典的正文本身就是一個(gè)聚集索引(按照拼音的英文字母排序) 比如,我們要查“安”字 ,就會(huì )很自然地翻開(kāi)字典的前幾頁(yè),因為“安”的拼音是“an”,而按照拼音排序漢字的字典是以英文字 母“a”開(kāi)頭并以“z”結尾的,那么“安”字就自然地排在字典的前部。如果您翻完了所有以“a”開(kāi)頭的部分仍然找不到這個(gè)字,那么就說(shuō)明您的字典中沒(méi)有這個(gè)字;同樣的,如果查“張”字,那您也會(huì )將您的 字典翻到最后部分,因為“張”的拼音是“zhang”。也就是說(shuō),字典的正文部分本身就是一個(gè)目錄,您不需要再去查其他目錄來(lái)找到您需要找的內容。我們把這種正文內容本身就是一種按照一定規則排列的目錄稱(chēng)為“聚集索引”。 這也是為什么一張表只能 夠有一個(gè)聚集索引的原因。因為一張表只能夠按一種方式排序。 其中聚集索引的葉級節點(diǎn)就是數據。你可以理解為有很多列火車(chē),按照火車(chē)頭索引(排序),火車(chē)頭后面跟著(zhù)的就是數據。
如果您認識某個(gè)字,您可以快速地從自動(dòng)中查到這個(gè)字。但您也可能會(huì )遇到您不認識的字,不知道它的發(fā)音,這時(shí)候,您就不能按照剛才的方法找到您要查的字,而需要去根據“偏旁部首”查到您要找的字,然后根據這個(gè)字后的頁(yè)碼直接翻到某頁(yè)來(lái)找到您要找的字。但您結合“部首目錄”和“檢字表”而查到的字的排序并不是真正的正文的排序方法,比如您查“張”字,我們可以看到在查部首之后的檢字表中“張” 的頁(yè)碼是672頁(yè),檢字表中“張”的上面是“馳”字,但頁(yè)碼卻是63頁(yè),“張”的下面是 “弩”字,頁(yè)面390頁(yè)。很顯然,這些字并不是真正的分別位于“張”字的上下方,現在您看到的連續的“馳、張、弩” 三字實(shí)際上就是他們在非聚集索引中的排序,是字典正文中的字在非聚集索引中的映射。我們可以通過(guò)這種方式來(lái)找到您所需要的字,但它需要兩個(gè)過(guò)程,先找到目錄中的結果,然后再翻到您所需要的頁(yè)碼。我們把這種目錄純粹是目錄,正文純粹是正文的排序方式稱(chēng)為“非聚集索引”。
實(shí)際上如果表上有聚集索引,則非聚集索引中存儲著(zhù)聚集索引的引用,然后通過(guò)利用聚集索引來(lái)獲取數據。因此這就是為什么返回少量數據的時(shí)候使用非聚集索引的性能較好,而返回大量的數據的時(shí)候使用非聚集索引還不如直接全表掃描來(lái)得快。而如果表上沒(méi)有聚集索引的時(shí)候,則引用行號。
非聚集索引需要額外的空間進(jìn)行存儲,按照被索引列進(jìn)行聚集索引,并在B樹(shù)的葉子節點(diǎn)包含指向非聚集索引所在表的指針。非聚集索引也是B樹(shù)結構,另外一個(gè)單獨的B樹(shù)。
唯一索引:
當主鍵創(chuàng )建時(shí)如果不設置為聚集索引,那么就一定是唯一的非聚集索引。實(shí)際上,唯一索引,故名思議就是它要求該列上的值是唯一的。
聚集索引列可以重復,非聚集索引列也可以重復。這就是為什么要有唯一這個(gè)東東了。聲明唯一索引的語(yǔ)法很簡(jiǎn)單,只是多了個(gè)UNIQUE關(guān)鍵字。
CREATE UNIQUE NONCLUSTERED INDEX [AK_Product_Name] ON Production.Product ( [Name] );
唯一索引有很多限制和特性。下面詳細學(xué)習下唯一索引。
為表聲明主鍵或唯一約束時(shí),SQL Server會(huì )自動(dòng)創(chuàng )建與之對應的唯一索引。定義一個(gè)唯一約束時(shí),SQL Server會(huì )自動(dòng)創(chuàng )建一個(gè)與之同名的唯一索引,要刪除索引必須先刪除約束。但刪除約束,刪除約束也會(huì )導致與之關(guān)聯(lián)的索引被刪除,也就是說(shuō),不能刪除唯一索引,要刪除索引只有刪除唯一約束這個(gè)辦法。
唯一索引依賴(lài)于唯一約束,刪除唯一索引必須刪除唯一約束。另外SQL Server又在建立唯一約束時(shí)又默認建立唯一索引。
總結起來(lái)就是:唯一索引與唯一約束始終一同存在。
因為定義一個(gè)主鍵或是定義約束會(huì )導致索引被創(chuàng )建,所以你必須在約束定義時(shí)就給出必要的索引信息,因此上面ALTER TABLE語(yǔ)句中包含了”CLUSTERED”關(guān)鍵字。
ALTER TABLE Production.Product ADD CONSTRAINT PK_Product_ProductID PRIMARY KEY CLUSTERED ( ProductID );
如果唯一索引或約束所約束的列在當前的表中已經(jīng)含有了重復值,那么創(chuàng )建索引會(huì )失敗。而當唯一索引創(chuàng )建成功后,所有違反這個(gè)約束的INSERT、UPDATE語(yǔ)句都會(huì )失敗。
消息 2601,級別 14,狀態(tài) 1,第 1 行 不能在具有唯一索引 'AK_Product_Name' 的對象 'Production.Product' 中插入重復鍵的行。 語(yǔ)句已終止。 唯一約束和唯一索引并沒(méi)有顯著(zhù)的區別。創(chuàng )建獨立的唯一索引和使用唯一約束對于數據的驗證方式并無(wú)區別。查詢(xún)優(yōu)化器也不會(huì )區分唯一索引是由約束創(chuàng )建還是手工創(chuàng )建。然而以數據完整性為目標的話(huà),最好創(chuàng )建約束,這使得對應的索引的目標一目了然。
過(guò)濾唯一索引,當我們需要既允許多個(gè)NULL值,又不允許重復的時(shí)候,可以使用這個(gè):
CREATE UNIQUE NONCLUSTERED INDEX xx on ProductDemo(<索引列>) --指定索引列 where <索引列>!=null) --過(guò)濾條件
對于用以上語(yǔ)法創(chuàng )建的唯一索引,插入時(shí),只有當唯一索引列不為NULL的時(shí)候才檢測重復。換句話(huà)說(shuō),以上表的索引列允許多個(gè)NULL值。
聯(lián)系客服