索引是數據庫設計的基礎,並告訴開發人員使用數據庫關於設計者的意圖。不幸的是,當性能問題出現時,索引每每被添加爲過後考慮。這裏最後是一個簡單的系列文章,應該使他們快速地使任何數據庫專業人員「快速」sql
第一級引入SQL Server索引:使SQL Server可以在最短的時間內找到和/或修改請求的數據的數據庫對象,使用最少的系統資源來實現最高性能。良好的索引也將容許SQL Server實現最大的併發性,以便由一個用戶運行的查詢對其餘人運行的查詢影響不大。最後,經過在建立惟一索引時保證鍵值的惟一性,索引提供了強制執行數據完整性的有效方式。這個級別是一個介紹;它涵蓋了概念和用法,但將物理細節留在較晚的級別。數據庫
對於數據庫開發人員來講,深刻理解索引是很是重要的:出於某種緣由,數據庫開發人員最重要的是:當SQL Server的請求從客戶端到達時,SQL Server只有兩種可能的方式來訪問請求的行:併發
l ·它能夠掃描包含數據的表中的每一行,從第一行開始並繼續到最後一行,檢查每一行,看它是否符合請求標準。數據庫設計
l ·或者,若是有有用的索引可用,則可使用索引來查找所請求的數據。性能
第一個選項老是可用於SQL Server。第二個選項僅在您指示SQL Server建立有益的索引時纔可用,但能夠顯着提升性能,咱們將在後面的層次中進行說明。ui
因爲索引具備與它們相關的開銷(它們佔用空間而且必須與表保持同步),所以SQL Server不須要它們。能夠有一個沒有索引的數據庫。它可能執行得不好,確定會有數據完整性問題,但SQL Server將容許它。spa
可是,這不是咱們想要的。咱們都但願數據庫性能良好,具備數據完整性,同時將索引開銷降到最低。這個水平將使咱們朝着這個目標前進。設計
示例數據庫對象
在整個StairWay中,咱們將用例子來講明關鍵的概念。這些示例基於Microsoft AdventureWorks示例數據庫。咱們專一於銷售訂單功能。五張表將給咱們交易和非交易數據的良好組合; Customer,SalesPerson,Product,SalesOrderHeader和SalesOrderDetail。爲了保持重點,咱們使用列的一個子集。blog
AdventureWorks已經正常化了,因此銷售人員信息被分紅三個表格。營業員,員工及聯繫方式。對於一些例子,咱們將把它們看成一個表格。圖1.1顯示了咱們將要使用的一整套表格以及它們之間的關係。
圖1.1:將在此階梯中使用的AdventureWorks表
注意:
該樓梯級別顯示的全部TSQL代碼能夠與文章一塊兒下載(請參閱本文底部的連接)
什麼是索引?
咱們以一個簡短的故事開始咱們的索引研究,這個故事使用了一個陳舊的,但已經證明的技術,在咱們介紹索引的基本概念時,咱們將在本文中引用這個故事。
你離開你的房子跑幾個差事。當你回來的時候,你會發現女兒的壘球教練正在等你的消息。特蕾西,麗貝卡和艾米中的三個女孩已經失去了球隊的帽子。你能夠請運動產品商店擺動,併爲女孩買帽子。他們的父母將在下一場比賽中報銷你。 你知道女孩,你知道他們的父母。但你不知道他們的帽子大小。大家鎮的某個地方有三個住宅,每一個住宅都有你須要的信息。沒問題,你只需打電話給父母,並得到帽子大小。您接觸到您的電話,而後到達索引 - 電話號碼簿的白頁。你須要的第一個住所是海倫·邁耶(Helen Meyer)。估計「邁爾」將位於人口中間附近,你跳到白頁的中間,只是發現你在標題爲「Kline-Koerber」的頁面上。你向前跳一小步,到達「Nagle-Nyeong」頁面。一個更小的跳躍,讓你在「馬爾多納多 - 納格爾」頁面。意識到你如今在正確的頁面,你掃描頁面,直到你到達「邁爾,海倫」線,並得到電話號碼。使用電話號碼,您能夠到達Meyer住宅並獲取所需的信息。 你再重複這個過程兩次,到另外兩個住所,再得到兩個帽子尺寸。
您剛剛使用了一個索引,而且已經以與SQL Server使用索引相同的方式使用它;由於白頁和SQL Server索引之間有很大的類似之處和一些區別。
實際上,剛剛使用的索引表明SQL Server支持的兩種SQL Server索引中的一種:聚簇和非聚簇。白頁最能表明非彙集索引的概念。所以,在這個層面上,咱們引入非彙集索引。隨後的級別將引入彙集索引並深刻鑽取這兩種類型。
非彙集索引
白頁相似於非彙集索引,由於它們不是數據自己的組織;而是一種機制或地圖來幫助您訪問這些數據。數據自己就是咱們須要聯繫的實際人員。電話公司沒有按照有意義的順序安排小鎮的住宅,把房子從一個地方搬到另外一個地方,這樣同一個壘球隊的全部女孩就住在一塊兒,房子也沒有居民的姓氏。相反,它會給你一本書,每一個住所都有一個入口。這些條目按照白頁的搜索鍵進行排序;姓氏,名字,中間首字母和街道地址。每一個條目都包含搜索關鍵字和數據,使您可以進入住所;電話號碼。
像白名單中的條目同樣,SQL Server非聚簇索引中的每一個條目都由兩部分組成:
l ·搜索關鍵字,例如姓氏 - 名字 - 中間首字母。 。在SQL Server術語中,這是索引鍵。
l ·書籤與電話號碼具備相同的用途,容許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都會告訴咱們在檢索請求的信息方面已經作了多少工做。咱們將在咱們的Contact表中找到「Helen Meyer」行(她的行位於表格中間附近)。最初,該表在「名字」列或「姓氏」列中將不具備索引。爲確保您能夠屢次運行該示例,請確保咱們將在第三批生成的索引不存在,方法是運行如下代碼:
IF EXISTS (SELECT * FROM sys.indexesWHERE OBJECT_ID = OBJECT_ID('Person.Contact')
AND name = 'FullName')DROP INDEX Person.Contact.FullName;
Listing 1.1 - Ensuring the index does not exist
Our task will require four SQL command batches.
The first command batch:
SET STATISTICS io ON
SET STATISTICS time ONGO
清單1.2 - 打開統計信息
上面的批處理通知SQL Server咱們但願咱們的查詢做爲輸出的一部分返回性能信息。
第二批命令:
SELECT *
FROM Person.Contact
WHERE FirstName = 'Helen'
AND LastName = 'Meyer';GO
清單1.3 - 檢索一些數據
這第二批檢索「海倫邁耶」行:
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;而且須要很是少許的處理器時間來檢索「海倫邁耶」行。
結論
建立精心挑選的索引能夠大大提升數據庫性能。在下一個層面,咱們將開始考察索引的物理結構。咱們將研究爲何這個非彙集索引對這個查詢是如此有利,爲何這可能不老是如此。將來的水平將涵蓋其餘類型的指數,指數的額外收益,與指數相關的成本,監測和維護您的指數,以及最佳作法;全部的目標都是爲您提供必要的知識,爲您本身的數據庫中的表建立最佳的索引方案。
可下載的代碼
l Level1 - IntroToIndexes_Durant_Code.sql
l LevelLevel 1 - MillionRowContactTable.sql
資源:
Level 1 - IntroToIndexes_Durant_Code.sql | 1級 - MillionRowContactTable.sql
本文是SQL Server索引階梯的一部分