SQL Server索引簡介:SQL Server索引進階 Level 1

做者:David Durant,2014/11/05(首次發佈:2011/02/17)sql

關於系列

本文屬於進階系列的:Stairway to SQL Server Indexes數據庫

索引是數據庫設計的基礎,並告訴開發人員使用數據庫大量關於設計人員的意圖。不幸的是,當性能問題出現時,索引一般被添加爲過後的想法。最後這一系列簡單的文章,應該能使任何數據庫專業人員快速的「加快速度」。併發


此第一級引入SQL Server索引:數據庫對象,使SQL Server可以在最短期內查找和/或修改所請求的數據,使用最少的系統資源實現最大性能。良好的索引還將容許SQL Server實現最大的併發性,以便一個用戶運行的查詢對其餘人運行的查詢幾乎沒有影響。最後,索引提供了一種實現數據完整性的有效方法,經過在建立惟一索引時保證鍵值的惟一性。這個級別是一個介紹;它涵蓋了概念和用法,但將物理細節留給了更高的層次。數據庫設計

對數據庫開發人員的透徹理解對於數據庫開發人員來講很是重要,其中一個緣由來自於全部其餘緣由:當SQL Server從客戶端到達的請求時,SQL Server只有兩種可能的方式來訪問所請求的行:sqlserver

  • 它能夠掃描包含數據的表中的每一行,從第一行開始,並繼續到最後一行,檢查每一行以查看它是否符合請求標準。
  • 或者,若是有益的索引可用,則可使用索引來定位所請求的數據。
    第一個選項始終可用於SQL Server。第二個選項只有在您指示SQL Server建立有益的索引時纔可用,但能夠顯着提升性能,由於咱們稍後會在此級別進行說明。

由於索引具備與它們相關聯的開銷(它們佔用空間而且必須與表保持同步),因此它們不是SQL Server所必需的。徹底沒有索引的數據庫是可能的。它可能會執行得不好,必定會有數據完整性問題,但SQL Server將容許它。性能

可是,這不是咱們想要的。咱們都但願數據庫運行良好,具備數據完整性,同時將索引開銷降至最低。這個水平將使咱們開始實現這一目標。spa

樣例數據庫

在這個樓梯中,咱們將用例子來講明關鍵概念。 這些示例基於Microsoft AdventureWorks示例數據庫。 咱們專一於銷售訂單功能。 五個表將給咱們很好的組合事務和非交易數據; 客戶,SalesPerson,產品,SalesOrderHeader和SalesOrderDetail。 爲了保持重點,咱們使用一列子集。設計

AdventureWorks正常化,因此銷售人員信息被分爲三個表格: 銷售人員,員工和聯繫人。 對於一些例子,咱們將它們視爲單個表。 咱們將使用的完整的表,以及它們之間的關係,如圖1.1所示。
code

圖1.1:將在此樓梯中使用的AdventureWorks表server

注意:
此樓梯級別中顯示的全部TSQL代碼能夠與文章一塊兒下載(請參閱本文底部的連接)

什麼是索引?

咱們開始對索引的研究,一個簡短的故事,一個使用一箇舊的並且被證實的技術,咱們在本文中將引用索引的基本概念。

你離開你的房子跑幾個差事。當你回來的時候,你會發現你女兒壘球教練的消息等着你。三個女孩,特雷西,麗貝卡,艾米已經失去了球隊帽。你能擺脫競技產品店,買女孩的帽子。他們的父母會在下一場比賽中報銷你。

你知道女孩,你知道他們的父母。但你不知道他們的帽子大小。在你鎮的某個地方有三個住宅,每一個都有一個您須要的信息。沒問題,你只要打電話給父母,獲得帽子的大小。您能夠撥打手機,而後到達索引 - 電話簿的白頁。

您須要達到的第一個住所是Helen Meyer。估計「邁耶」將位於人口中部附近,你跳到白頁的中間;只發現你在頁面上的標題爲「Kline-Koerber」。你進一步向前跳,到達「Niger-Nyeong」頁面。一個甚至更小的跳躍讓你進入「馬爾多納多 - 尼格爾」頁面。意識到您如今在正確的頁面,您掃描頁面,直到您到達「邁耶,海倫」行並得到電話號碼。使用電話號碼,您能夠到達邁耶居所,並獲取您須要的信息。

您再重複一次這個過程,再到另外兩個居住地,再得到兩個帽子大小。

你剛剛使用了一個索引,而且使用它與SQL Server使用索引的方式大體相同。由於有很大的類似之處,以及白皮書和SQL Server索引之間的一些區別。
實際上,您剛剛使用的索引表明SQL Server支持的兩個SQL Server索引類型:集羣和非聚簇。白頁最好表明非聚簇索引的概念。所以,在這個層次上,咱們引入非聚簇索引。後續級別將引入集羣索引,並對這兩種類型進行更深刻的挖掘。

非聚簇索引

白頁相似於非聚簇索引,由於它們不是數據自己的組織;而是一種機制或地圖來幫助您訪問該數據。數據自己就是咱們須要聯繫的實際人員。電話公司不會安排該鎮的住宅有意義的順序,將房屋從一個位置移動到另外一個位置,以使同一壘球隊中的全部女孩彼此隔壁相隔,房屋不按居民姓氏組織。相反,它給你一本書包含每一個住所的一個條目。這些條目由白頁的搜索關鍵字排序;姓氏,名字,中間初始和街道地址。每一個條目都包含搜索關鍵字和使您能夠訪問住所的數據;電話號碼。

像一個條目白皮書,SQL Server非聚簇索引中的每一個條目都包含兩部分:

  • 搜索鍵,如姓氏 - 名字 - 中間初始。 。在SQL Server術語中,這是索引鍵。
  • 書籤與電話號碼相同,容許SQL Server直接導航到與該索引條目對應的表中的行。

此外,SQL Server非聚簇索引條目具備一些僅內部使用的頭信息,而且可能包含一些可選信息。這兩個都將在之後的層面上予以涵蓋;此時對於非聚簇索引的理解也不重要。

像白頁同樣,在搜索關鍵字序列中維護一個SQL Server索引,以即可以在一組小的「跳轉」中訪問任何特定的條目。給定搜索關鍵字,SQL Server能夠快速獲取該密鑰的索引條目。與白頁不一樣,SQL Server索引是動態的。也就是說,SQL Server會在每次添加,刪除行或修改搜索關鍵字列值時更新索引。

正如白頁中的條目序列與城鎮內的住宅地理序列不一樣;非聚簇索引中的條目序列與表中的行序列不一樣。索引中的第一個條目多是表中最後一行,索引中的第二個條目多是表中第一行。若是事實與索引不一樣,索引始終是有意義的序列;表的行能夠徹底沒有排序。

建立索引時,SQL Server會在基礎表中的每一行的索引中生成並維護一個條目(當覆蓋過濾後的索引時,將會遇到此通用規則的一個例外)。您能夠在表上建立多個非聚簇索引,但不能包含包含來自多個表的數據的索引。

而最大的區別是:SQL Server不能使用電話。它必須使用索引條目的書籤部分中的信息導航到表的相應行。當SQL Server須要數據行中的任何信息,但不在相應的索引條目中時,這將是必需的,例如Tracy Meyer的壘球帽大小。因此,爲了更好的比喻,白頁的條目包含一組GPS座標而不是一個電話號碼。而後,使用GPS座標導航到由白頁條目表示的住宅。

創造和受益於非彙集索引

咱們經過兩次查詢咱們的示例數據庫來結束這個級別。 確保您正在使用適用於SQL Server 2005的AdventureWorks版本,可由SQL Server 2008使用。AdventureWorks2008數據庫具備不一樣的表結構,下面的查詢將失敗。 咱們每次都會運行相同的查詢; 但在咱們在表上建立一個索引以前,第一個執行將會發生,第二個執行將在咱們建立一個索引以後。 每次SQL Server會告訴咱們在檢索所請求的信息方面作了多少工做。 咱們將在咱們的聯繫表中找到「Helen Meyer」行(她的行位於表的中間附近)。 最初,表不會在FirstName列或LastName列上有一個索引。 爲確保您能夠屢次運行示例,請確保咱們將在第三批中構建的索引不存在,方法是運行如下代碼:

IF EXISTS (SELECT * FROM sys.indexes
WHERE OBJECT_ID = OBJECT_ID('Person.Contact')
AND name = 'FullName')
DROP INDEX Person.Contact.FullName;

清單1.1 - 確保索引不存在

咱們的任務將須要四個SQL命令批處理。

第一個命令批次:

SET STATISTICS io ON
SET STATISTICS time ON
GO

清單1.2 - 開啓統計

上述批次通知SQL Server,咱們但願咱們的查詢做爲輸出的一部分返回性能信息。

第二個命令批次:

SELECT *
    FROM Person.Contact
    WHERE FirstName = 'Helen'
        AND LastName = 'Meyer';
GO

清單1.3 - 檢索一些數據

第二批檢索「Helen Meyer」行:

584 Helen Meyer helen2@adventure-works.com   0-519-555-0112

再加上如下性能信息:

Table 'Contact'. Scan count 1, logical reads 569.
SQL Server Execution Times:   CPU time = 3 ms.

該輸出通知咱們,咱們的請求執行了569個邏輯IO,而且須要大約3毫秒的處理器時間來執行此操做。 您的處理器時間值可能不一樣。

第三個命令批次:

CREATE NONCLUSTERED INDEX FullName
            ON Person.Contact
    ( LastName, FirstName );
GO

清單1.4 - 建立非彙集索引

此批次在聯繫人表的名字和姓氏列上建立非聚簇複合索引。 複合索引是具備多個列的索引,肯定索引行序列。

第四個命令批次:

SELECT *
    FROM Person.Contact
    WHERE FirstName = 'Helen'
        AND LastName = 'Meyer';
GO

清單1.3(再次)

最後一批是從新執行咱們原始的SELECT語句。 咱們獲得與之前同樣返回的同一行; 可是此次性能統計數據是不一樣的

Table 'Contact'. Scan count 1, logical reads 4.
SQL Server Execution Times:   CPU time = 0 ms.

該輸出通知咱們,咱們的請求只須要4個邏輯IO; 而且須要很是少許的處理器時間來檢索「Helen Meyer」行。

結論

建立精心挑選的索引能夠大大提升數據庫性能。 在下一級,咱們將開始研究索引的物理結構。 咱們將研究爲何這個非彙集索引對這個查詢是如此有益的,爲何可能並不老是這樣。 將來的水平將涵蓋其餘類型的指數,指數的附加利益,與索引相關的成本,監控和維護您的指數以及最佳作法; 全部這些都旨在爲您提供必要的知識,爲您本身的數據庫中的表建立最佳的索引計劃。

代碼下載

Resources:

Level 1 - IntroToIndexes_Durant_Code.sql | Level 1 - MillionRowContactTable.sql

相關文章
相關標籤/搜索