原文連接:http://www.sqlservercentral.com/articles/Stairway+Series/72286/sql
By David Durant, 2017/10/18 (first published: 2014/11/26)數據庫
經過大衛·杜蘭特,2017/10/18(第一次出版:2014/11/26)服務器
本文是樓梯系列的一部分:SQL Server的階梯索引數據庫設計
索引數據庫設計的基礎,告訴開發人員使用數據庫設計者的意圖。 不幸的是索引時每每是後加上的性能問題出現。 終於在這裏是一個簡單的系列文章,應該讓任何數據庫專業迅速「加速」sqlserver
SQL Server的一級索引樓梯介紹了SQL Server索引,通常來講,和非彙集索引。 做爲咱們的第一個案例研究中,咱們演示了索引的潛在好處,當從一個表中檢索單個行。 在這個層面上,咱們繼續咱們的調查的非彙集索引; 檢查他們的貢獻好的查詢性能的狀況下,超越從一個表中檢索單個行。性能
將在大多數咱們的水平,咱們引入少許的理論,研究一些指數內部爲了幫助解釋這個理論,而後執行一些查詢。 有或沒有執行這些查詢索引和性能報告統計數據,這樣咱們能夠查看指標的影響。測試
咱們將使用從AdventureWorks數據庫表的子集,咱們用於一級、集中聯繫表在這個水平。 咱們將使用一個指數FullName咱們用於一級指數,來講明咱們的觀點。 以確保咱們控制上的索引聯繫表,咱們會讓兩個表的副本dbo模式,只有構建FullName指數其中之一。 這將給咱們的控制環境:兩份表:一個與一個單一的非彙集索引,一個沒有任何索引。spa
注意:
全部TSQL代碼所示這樓梯水平能夠在文章底部的下載。設計
清單1中的代碼的副本Person.Contact表,咱們能夠隨時從新運行這個批處理咱們但願從一個「白紙」開始。指針
若是存在(選擇*從sys.tables&# 160;在哪裏OBJECT_ID=OBJECT_ID(「dbo.Contacts_index」))刪除表dbo.Contacts_index;去若是存在(選擇*從sys.tables&# 160;在哪裏OBJECT_ID=OBJECT_ID(「dbo.Contacts_noindex」))刪除表dbo.Contacts_noindex;去選擇*成dbo.Contacts_index從Person.Contact;選擇*成dbo.Contacts_noindex從Person.Contact;
清單2.1:複製人。 聯繫表
的一個片斷聯繫人表所示:
ContactID FirstName MiddleName LastName EmailAddress
。
。
1288年勞拉·F·諾曼laura1@adventure-works.com
651年邁克爾彭定康michael20@adventure-works.com
1652伊莎貝拉R詹姆斯isabella6@adventure-works.com
1015年大衛·R·坎貝爾david8@adventure-works.com
1379年Balagane Swaminath balaganesan0@adventure-works.c
742年史蒂夫•施密特steve3@adventure-works.com
1743年香農C郭shannon16@adventure-works.com
1106年約翰·Y陳john2@adventure-works.com
1470年布萊恩Dockter blaine1@adventure-works.com
833年克拉倫斯·R。 Tatman clarence0@adventure-works.com
1834希瑟·吳heather6@adventure-works.com
丹尼斯·H·史密斯1197 denise0@adventure-works.com
560年詹妮弗·J。 Maxham jennifer1@adventure-works.com
1561年被罩Ben-Sacha ido1@adventure-works.com
924年貝基R。 水域becky0@adventure-works.com
。
下面的語句建立咱們的Contacts_index FullName非彙集索引表。
建立索引FullName在Contacts_index(姓,FirstName);
清單2.2 -建立一個非彙集索引
記住一個非彙集索引存儲索引鍵,以及一個書籤用來訪問表中的實際數據自己。 你能想到的書籤做爲一種指針。 將來的水平將描述書籤,其形式和使用,詳細。
的一個片斷FullName指數顯示,組成的姓和FirstName做爲鍵列,加上書籤:
——搜索鍵列:書籤
Russell Zachary =>
Ruth Andy =>
Ruth Andy =>
Ryan David =>
Ryan Justin =>
Sabella Deanna =>
Sackstede Lane =>
Sackstede Lane =>
Saddow Peter =>
Sai Cindy =>
Sai Kaitlin =>
Sai Manuel =>
Salah Tamer =>
Salanki Ajay =>
Salavaria Sharon => 每一個條目包含索引鍵列和收藏價值。 此外,SQL Server非彙集索引條目有internal-use-only頭信息和可能包含一些可選的數據值。 這些將在之後的水平; 也不是重要的在這個時候非彙集索引的基本理解。
如今,咱們須要知道的是,鍵值使SQL Server可以找到合適的索引條目(年代); 和條目的收藏價值使得SQL Server訪問相應的數據表中的行。
索引條目排序的索引鍵值(s),那麼SQL Server能夠快速遍歷順序條目。 的掃描序列條目能夠開始從一開始的指數,指數,指數中或從任何條目。
所以,若是一個請求要求全部聯繫人的姓開頭字母「S」(LastName像' S % '),SQL Server能夠快速導航到第一個「S」條目(「Sabella,迪安娜」),而後遍歷索引,使用書籤訪問的行,直到到達第一個「T」條目; 這時它知道它檢索全部的「S」條目。
上述請求執行更快若是全部選中的列索引。 所以,若是咱們發佈:
選擇FirstName,姓從聯繫在哪裏姓就像' S %;
SQL Server能夠快速導航到第一個「S」條目,而後遍歷索引條目,忽略了書籤和檢索數據值直接從索引條目,直到它到達第一個「T」條目。 在關係數據庫術語中,該指數「覆蓋」查詢。
任何SQL操做符的好處從測序數據能夠從索引中受益。 這包括ORDER BY、組,不一樣的聯盟(聯盟),並加入…。
例如,若是請求要求計數的聯繫人的姓,SQL Server能夠在第一項開始計數,並進行指數。 每次姓的價值變化,SQL Server輸出當前計數,並開始一個新的計數。 與前面的請求,這是一個覆蓋查詢; SQL Server訪問索引,徹底忽略了表。
注意從左到右的順序的重要性的關鍵列。 咱們的指數是很是有用的,若是一個請求要求每一個人的姓「艾什頓」,但不多或根本沒有幫助若是請求是對每一個人都是誰的名字「艾什頓」。
若是你想執行測試查詢,確保你運行該腳本建立兩個版本新聯繫表,dbo.Contacts_index和dbo.Contacts_noindex;建立並運行腳本名,姓指數dbo.Contacts_index。
驗證斷言在前面的小節中,咱們將在相同的性能統計數據,咱們使用1級和運行一些查詢; 有和沒有索引。
設置數據io在
設置數據時間在
由於聯繫人表的AdventureWorks數據庫中只有19972行,它將很可貴到有意義的統計值。 咱們大多數的查詢會顯示CPU時間值爲0,因此咱們不顯示統計數據的輸出時間; 只從統計數字IO,反映了可能的頁面數量必須閱讀。 這些值將使咱們可以比較查詢在相對意義上,肯定哪些查詢與索引比別人表現得更好。 若是你想要一個更大的表更現實的計時測試,腳本構建版本的一百萬行聯繫本文表是可用的。 全部的討論將假設您使用的是標準的19972 -行表。
咱們的第一個查詢將被索引的查詢; 一個檢索一組有限的列的全部聯繫人的姓始於「S」。 表2.1中給出了查詢執行信息。
SQL |
選擇FirstName、LastName |
沒有索引 |
(2130行受影響) |
與指數 |
(2130行受影響) |
指數的影響 |
從568年讀14讀IO減小。 |
評論 |
覆蓋索引查詢是一件好事。 沒有索引,找到掃描整個錶行。 |
表2.1:覆蓋查詢運行時執行結果
接下來,咱們修改咱們的查詢請求與以前相同的行,但不包括列索引。 表2.2中給出了查詢執行信息。
SQL |
SELECT * |
沒有索引 |
與以前的查詢相同。 (由於它是一個表掃描)。 |
與指數 |
(2130行受影響) |
指數的影響 |
根本沒有影響。 |
評論 |
該指數是查詢的執行期間從未使用過! |
表2.2:non-covered查詢運行時執行結果
這一次,咱們讓咱們的查詢更多的選擇性; 也就是說,咱們縮小被請求的行數。 這增長的機率指數將有利於查詢。 表2.3中給出了查詢執行信息。
SQL |
SELECT * |
沒有索引 |
與以前的查詢相同。 (由於它是一個表掃描)。 |
與指數 |
(107行受影響) |
指數的影響 |
IO減小從568年讀111讀. . |
評論 |
SQL Server 107年訪問「Ste %」條目,都是坐落在指數連續。 每一個條目的書籤被用來檢索到相應的行。 行不位於連續在桌子上。 這個查詢索引受益; 但不是它受益第一個查詢,查詢「覆蓋」; 尤爲是所須要的IOs數檢索每一行。 你可能會認爲,閱讀107索引條目須要107 + 107 + 107行。 爲何只有111讀取被要求將覆蓋在一個更高的水平。 如今,咱們不多會說,讀的是用於訪問索引條目; 大部分被用來訪問的行。 由於前面的查詢請求的2130行,沒有受益於指數; 這個查詢,要求107行,受益於指數——您可能還想「臨界點又在何方? 「SQL Server的決定背後的計算也將在將來的水平。 |
表2.3:更多的選擇性non-covered查詢運行時執行結果
咱們最後將一個聚合查詢樣例查詢; 是一個查詢,涉及計算,總計平均等等。 在這種狀況下,它是一個查詢,告訴咱們名字的範圍內重複聯繫表。
結果,在某種程度上,是這樣的:
鋼美林1
斯蒂爾瓊1
斯蒂爾勞拉2
斯蒂爾曼Shanay 1
Steen海蒂2
蒂芬妮斯特凡諾1
施泰納Alan 1
查詢執行信息表2.4中能夠看到。
SQL |
選擇名,姓,COUNT(*)「聯繫人」 |
沒有索引 |
與以前的查詢相同。 (由於它是一個表掃描)。 |
與指數 |
(104行受影響) |
指數的影響 |
從568年讀到4讀IO減小。 |
評論 |
所需的全部信息的查詢索引; 是在理想的指數序列計算數量。 全部的「姓始於Ste」條目中連續指數; 和組內,一個姓/名值的全部條目被組合在一塊兒。 不須要訪問的表; 也不是任何排序所需的中間結果。 再次,索引,查詢是一件好事。 |
表2.4:當運行覆蓋聚合查詢執行結果
若是咱們改變查詢包括列索引,咱們獲得了性能結果見表2.5。
SQL |
選擇LastName、FirstName MiddleName,COUNT(*)「聯繫人」 |
沒有索引 |
與以前的查詢相同。 (由於它是一個表掃描)。 |
與指數 |
(105行受影響) |
指數的影響 |
IO減小從568年讀111讀; 之前同樣non-covered查詢 |
評論 |
中間工做處理查詢時並不老是出如今統計數據。 技術,使用內存或tempdb排序和合並數據的例子。 在現實中,索引的好處可能大於所示的統計信息。 |
表2.5:noncovered聚合查詢運行時執行結果
咱們如今知道非彙集索引具備如下特性。 非彙集索引:
和咱們看到的例子中,SQL Server從索引就能夠知足要求; 和它徹底忽略了指數; 還有一些經常使用的索引和表的組合。 出於這個緣由,咱們關閉二級經過更新語句在一級的開始。
當一個請求到達您的數據庫,SQL Server只有三個可能的方法來訪問數據要求的聲明:
通常來講,第一個是理想; 和第二個比第三個。 在即將到來的水平,咱們顯示如何增長您的索引的機率將覆蓋你的熱門查詢,以及如何肯定你non-covered足夠選擇性受益於您的索引查詢。 但這將須要更多的詳細信息索引的內部結構比咱們尚未。
才能達到這一點,咱們須要引入其餘類型的SQL Server指數; 彙集索引。 這是三級的主題。
二級- NonClustered.sql|Level2_MillionRowContactTable.sql
這篇文章的一部分SQL Server的階梯索引樓梯