久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

SQL Server索引有什么用

136次閱讀
沒有評論

共計 4781 個字符,預計需要花費 12 分鐘才能閱讀完成。

這篇文章給大家分享的是有關 SQL Server 索引有什么用的內容。丸趣 TV 小編覺得挺實用的,因此分享給大家做個參考,一起跟隨丸趣 TV 小編過來看看吧。

索引的概念

索引的用途:我們對數據查詢及處理速度已成為衡量應用系統成敗的標準,而采用索引來加快數據處理速度通常是最普遍采用的優化方法。

索引是什么:數據庫中的索引類似于一本書的目錄,在一本書中使用目錄可以快速找到你想要的信息,而不需要讀完全書。在數據庫中,數據庫程序使用索引可以重啊到表中的數據,而不必掃描整個表。書中的目錄是一個字詞以及各字詞所在的頁碼列表,數據庫中的索引是表中的值以及各值存儲位置的列表。

索引的利弊:查詢執行的大部分開銷是 I /O,使用索引提高性能的一個主要目標是避免全表掃描,因為全表掃描需要從磁盤上讀取表的每一個數據頁,如果有索引指向數據值,則查詢只需要讀少數次的磁盤就行啦。所以合理的使用索引能加速數據的查詢。但是索引并不總是提高系統的性能,帶索引的表需要在數據庫中占用更多的存儲空間,同樣用來增刪數據的命令運行時間以及維護索引所需的處理時間會更長。所以我們要合理使用索引,及時更新去除次優索引。

1. 聚集索引和非聚集索引

索引分為聚集索引和非聚集索引

1.1 聚集索引

表的數據是存儲在數據頁中(數據頁的 PageType 標記為 1),SqlServer 一頁是 8k,存滿一頁就開辟下一頁存儲。如果表有聚集索引,那么一筆一筆物理數據就是按聚集索引字段的大小升 / 降排序存儲在頁中。當對聚集索引字段更新或中間插入 / 刪除數據時,都會導致表數據移動(造成性能一定影響),因為它要保持升 / 降排序。

注意,主鍵只是默認是聚集索引,它也可以設置為非聚集索引,也可以在非主鍵字段上設置為聚集索引,全表只能有一個聚集索引。

一個優秀的聚集索引字段一般包含以下 4 個特性:

(A). 自增長

總是在末尾增加記錄,減少分頁和索引碎片。

(B). 不被更改

減少數據移動。

(C). 唯一性

唯一性是任何索引最理想的特性,可以明確索引鍵值在排序中的位置。

更重要的是,索引鍵指唯一的話,它在每條記錄里才可以正確指向源數據行 RID。如果聚集索引鍵值不唯一,SqlServer 就需要內部生成 uniquifier 列組合當作聚集鍵保證“鍵值”唯一性;如果非聚集索引鍵值不唯一,就會增加 RID 列(聚集索引鍵或者堆表中的行指針)保證“鍵值”唯一性。

思考(可略過):索引“鍵值”在非葉子節點也有保證唯一性,原因應該是為了明確索引記錄在非葉子節點中的位置。比如有個非聚集索引字段 Name2,表中有很多 Name2= a 的記錄,導致 Name2= a 在非葉子節點上有多條索引記錄(節點),這時候再 insert 一筆 Name2=‘a 的記錄時,就可以根據非葉子節點的 RID 和新增記錄的 RID 很快確定要 insert 到哪個索引記錄(節點)上,如果沒有非葉子節點的 RID,那得遍歷到所有 Name2= a 的葉子節點才能確定位置。另外,當我們 select * from Table1 where Name2 = a 時,返回的數據是按非聚集索引 Name2 和 RID 排序的,很好理解返回的數據就是按這邊索引存儲的順序排序的。這是這條 sql 查詢時有用到 Name2 索引的結果,如果數據庫查詢計劃因“臨界點”問題選擇直接表數據掃描,那返回的數據默認就是按表數據的順序排序的。

為了“鍵值”唯一性,對于聚集索引,uniquifier 列只在索引值重復時增加。對于非聚集索引,如果創建索引時沒定義唯一,RID 會在所有記錄增加,就算索引值是唯一的;如果創建索引時定義唯一,RID 只在葉子層增加,用于查找源數據行,即書簽查找操作。

(D). 字段長度小

聚集索引鍵長度越小,一頁索引頁就可以容納更多索引記錄,進而減少索引 B 樹結構的深度。例如,一個百萬記錄的表有一個 int 聚集索引,可能只需要 3 層的 B 樹結構。如果把聚集索引定義在更寬的列(比如 uniqueidentifier 列需要 16 字節),那么索引的深度會增加到 4 層。任何聚集索引查找需要 4 個 I / O 操作(確切的說是 4 個邏輯讀),原先只要 3 個 I / O 操作。
同樣,非聚集索引里會包含聚集索引鍵值,聚集索引鍵長度越小非聚集索引記錄也就越小,一頁索引頁就可以容納更多索引記錄。

1.2 非聚集索引

也是存儲在頁中(PageType 標記為 2 的頁,叫索引頁 )。比如表 T 建立了一個非聚集索引 Index_A,那么表 T 有 100 條數據的話,那么索引 Index_A 也就有 100 條數據(準確的說是 100 條葉子節點數據,索引是 B 樹結構,如果樹的高度大于 0,那么就有根節點頁或中間節點頁數據,這時索引數據就超過 100 條),如果表 T 還有非聚集索引 Index_B,那么 Index_B 也是至少 100 條數據,所以索引建越多開銷越大。

更新索引字段、插入一條數據、刪除一條數據都會造成索引的維護從而造成性能的一定影響。在不同情況下,性能影響是不同的。比如當你有一個聚集索引,插入的數據又都是在末尾,這樣幾乎是不會造成數據移動,影響較小;如果插入的數據在中間位置,一般會導致數據移動,而且可能產生分頁和頁碎片,影響就會稍大一點(如果插入到的中間頁有足夠的剩余空間容納插入的數據,而且位置是在頁末,也是不會造成數據移動)

2. 索引的結構

都說 SqlServer 的索引是 B 樹結構(這邊假定你對 B 樹結構有一定了解),那它到底長什么個模樣呢,可以用 Sql 語句來查看它的邏輯呈現。

新建查詢執行語法:DBCC IND(Test,OrderBo,-1) – 其中 Test 庫的 OrderBo 表有 1 萬筆數據,有聚集索引 Id 主鍵字段
(不妨自己動手建個表,有聚集索引字段,插入 1 萬表數據,然后執行這個語法看看,會收獲很多,百聞不如一見)

執行結果:

如上圖,看到一個 IndexLevel= 2 的索引頁 2112(這邊它就是 B 樹的根節點,IndexLevel 最大的就是根節點,往下就是子級、子子級 … 只有一個根頁作為 B 樹結構的訪問入口點),說明一定還有 IndexLevel= 1 的索引頁和 IndexLevel= 0 的葉子頁。由于這邊是聚集索引,因此當 IndexLevel= 0 的葉子頁就是數據頁,存儲的是一筆一筆的物理數據。如上圖也可以看到,IndexLevel= 0 的行的 PageType 等于 1,就是代表數據頁,上面 1.1 章節講到聚集索引時,也有提到 PageType=1;而如果是非聚集索引,IndexLevel= 0 的葉子頁,PageType 是等于 2,仍然是索引頁。

同樣,我們用 Sql 命令 DBCC PAGE 看一看

-- DBCC TRACEON(3604,-1) 
DBCC PAGE(Test,1,2112,3) 
 -- 根節點 2112,可以查出它的兩個子節點 2280 和 2448,然后對這兩個子節點再作 DBCC PAGE 查詢
DBCC PAGE(Test,1,2280,3) 
DBCC PAGE(Test,1,2448,3)

如上圖,IndexLevel= 2 的 2112 頁有兩個 IndexLevel= 1 的子節點 2280 和 2448,子節點下又有子節點,每個節點負責不同的索引鍵值的區間(即上圖的“Id(key)”欄位,第一行值是 Null,表示最小值或倒序時的最大值)。這樣的層級關系是不是就是一棵 B 樹結構,其中 IndexLevel 其實就是 B 樹結構中的高度 Height。

SqlServer 在索引中查找某一筆記錄時,是從根節點往下找到葉子節點,因為所有數據地址都有存在葉子節點,這其實是 B + 樹的特點之一(B 樹特點是如果查找的值在非葉子節點就找到,則就能直接返回,顯然 SqlServer 不是這么做,要驗證這一點你可以 set statistics io on 把統計開起來,然后 select 看下邏輯讀的次數)。

既然一定會找到葉子節點,那么索引包含列只要在葉子節點記錄就可以了,即非葉子節點沒有記錄包含列,“索引包含列”見下文第 3 章節。

B+ 樹這個特點(所有數據地址都有存在葉子節點)也利于 between value1 and value2 區間查詢,只要找到 value1 和 value2(在葉子節點),然后把中間串起來就是要的結果了。

SqlServer 索引結構更像是 B + 樹,最終是 B 樹和 B + 樹的混合版,數據結構都是人定的,不一定就是純粹的 B 樹或者單純的 B + 樹。

3. 索引包含列和書簽查找

談到索引,這邊再講一個 SqlServer2005 開始增加的“索引包含列”功能,很實用。

比如,在大報表查詢數據時,where 條件用到索引字段 Name2,但是要 select 的字段是 Name1,這時候可以使用“索引包含列”把 Name1 包含在索引字段 Name2 中,大大提高查詢性能。

語法:Create [UNIQUE]  Nonclustered/Clustered Index IndexName On dbo.Table1(Name2) Include(Name1);

接下來分析為什么索引包含列可以大大提高性能。仍然使用 DBCC PAGE 命令,查看一個非聚集索引并有包含列的索引數據情況:

由上圖可知,包含列 Name1 也存儲在索引數據中。因此,當數據庫用索引字段 Name2 定位到要查找的某一行時,就可以直接把 Name1 的值返回了,而不用再根據 RID(上圖是【HEAP RID(Key)】列)定位到數據頁中去取值,即減少了書簽查找。當查詢只返回一條數據,只有一次書簽查找時當然沒什么,如果查詢返回的數據很大,每一筆都要去數據頁找數據取出來,1000 筆就是 1000 次書簽查找,可想而知性能消耗很大,這時候“索引包含列”價值就大大體現出來了。

關于一次書簽查找,表有聚集索引(比如 Id)時就是類似執行了一次 select Name1 from Table1 where Id=1,利用聚集索引鍵 Id 查找(查找方式就是索引 Id 的 B 樹結構查找),而如果表沒有聚集索引,則是根據數據行指針(由“文件號 2byte:頁號 4byte:槽號 2byte”組成)查找。聚集索引鍵和行指針一般統稱為 RID(Row ID)指針。從這里我們可以想到,如果你的表沒有很好的聚集索引字段,建議自增長的 Id 字段做聚集索引主鍵(冗余出 Id 字段也行),它符合自增長、不被更改、唯一性、長度小的特性,是聚集索引的很好選擇。

自增長 Id 絕大部分情況下是適用的,特殊的情況看具體需求而定吧。還有自增長 Id 要考慮一個缺陷,當對表大數據量的并發 insert 記錄時,可以想象每個線程都是要 insert 到末尾那個頁,就會發生競爭和等待。解決這種情況你可以用 uniqueidentifier 類型字段(16 字節,我是不建議使用)或者哈希分區(就是一個表分成多個表,大數據處理中分庫分表是正常的)等。但是我建議先優化你的 insert 效率(insert 性能本身是很快的),測試每秒并發 insert 數是否滿足生產環境,以保留簡單穩定高效的自增長 Id 作法。

自增長 Id 不一定就是用數據庫提供的自增長,你也可以自己寫算法生成一個并發情況下也能唯一的 Id(這時候一般長度是 bitint,8 字節整形),這種情況適合場景是分布式數據庫中主從復制時 Id 欄位是要求一定不能出錯的情況(主從復制的一般模式下,主庫的 Id 是按主庫增長,從庫 Id 也是按從庫自己的增長,如果遇到死鎖等原因導致主從復制不同步時,那從庫的 Id 就和主庫的 Id 自增長就對不上號了)。如果自增長 Id 是冗余出的主鍵,那主從庫 Id 對不上號也就無影響。

另外,上圖最后一列【Row Size】還告訴我們,索引列或索引包含列的 size 不要太長,否則一頁容不了幾筆記錄,這樣大大增加了索引頁數量,而且索引數據所占的空間也大大增加了。

感謝各位的閱讀!關于“SQL Server 索引有什么用”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-07-28發表,共計4781字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 英山县| 探索| 商都县| 白山市| 彰武县| 策勒县| 金乡县| 琼结县| 富阳市| 微山县| 延寿县| 宁夏| 东丰县| 衡东县| 沙坪坝区| 伽师县| 武定县| 青海省| 怀来县| 措勤县| 东阿县| 侯马市| 平舆县| 镇远县| 常州市| 金阳县| 尤溪县| 灯塔市| 海林市| 定州市| 那曲县| 沅陵县| 息烽县| 武定县| 扎赉特旗| 阿图什市| 大港区| 厦门市| 河西区| 东阿县| 新宾|