索引舉例介紹

2021-08-24 19:50:48 字數 3761 閱讀 3278

description:查詢優化器在從表中查詢資料時,需要選擇乙個合適的訪問模式,在決定使用哪一種索引,使用掃瞄還是查詢,使用書籤查詢時,查詢優化器要考慮許多因素,這些因素包括:

下面通過乙個例子來介紹:

create table t (a int, b int, c int, d int, x char(200))

create unique clustered index ta on t(a)

create index tb on t(b)

create index tcd on t(c, d)

create index tdc on t(d, c)

插入一些資料:

set nocount on

declare @i int

set @i = 0

while @i < 100000

begin

insert t values (@i, @i, @i, @i, @i)

set @i = @i + 1

end無where條件

select a,b from t,

該 查詢不包含where條件語句,而使用掃瞄,可是這裡有兩種索引可用:聚集索引(ta)和非聚集索引(tb),這兩個索引均覆蓋a和b兩列,另外,聚集索 引也覆蓋c和x列.由於x列是字元型,長度為200個字元,聚集索引的每一行總寬度超過了200個位元組,對於每乙個8kb的頁面,儲存的行數也不超過40 行.而索引需要2500個頁來儲存所有10萬行資料,與之相反的是,非聚集索引中每一行的總寬僅有8個位元組,加一些頭部資訊,每一頁可以儲存上百行資料, 索引則需要不到250頁來儲存所有的10萬行資料.通過掃瞄非聚集索引,當執行查詢時則需要較少的i/o操作.因而使用的最佳計畫是:

|--index scan(object:([t].[tb]))

我們也可以使用sys.dm_db_index_physical_stats檢視來比較聚集索引與非聚集索引兩者所使用的頁數

select index_id, page_count

from sys.dm_db_index_physical_stats

(db_id('northwind'), object_id('t'), null, null, null)

執行上述查詢後,結果如下:

索引id號頁數1

2858

2174

3223

4223

從輸出結果可以看出,非聚集索引儲存行所使用的頁數明顯小於聚集索引使用的頁數.

當然我們也可以使用stats i/o和索引hints來比較聚集索引與非聚集索引的i/o數.

set statistics io on

select a, b from t with (index(ta))

表't'。掃瞄計數1,邏輯讀取2872次,物理讀取0 次,預讀0 次,lob 邏輯讀取0 次,lob 物理讀取0 次,lob 預讀0 次。

select a, b from t with (index(tb))

表't'。掃瞄計數1,邏輯讀取176次,物理讀取0 次,預讀0 次,lob 邏輯讀取0 次,lob 物理讀取0 次,lob 預讀0 次。

從stats i/o數可以看出,非聚集索引在獲取資料時,讀取較少的資料頁.

索引的選擇性

select a from t

where c > 150 and c < 160 and d > 100 and d < 200

此查詢有兩個不同的謂詞用於索引查詢,可以使用位於c列上的非聚集索引tcd,也可以使用位於d列上的非聚集索引tdc.

查詢優化器通過檢視兩個謂詞的選擇性來確定使用哪乙個索引,在c列上的謂詞選擇的行僅有9行,而在d列上則有99行,顯然使用索引tcd來評估位於d列上的residual謂詞比使用tdc索引的i/o開銷要小得多.

以下是該查詢的計畫:

|--index seek(object:([t].[tcd]), seek:([t].[c] > (150) and [t].[c] < (160)),

where:([t].[d]>(100) and [t].[d]<(200)) ordered forward)

索引查詢與索引掃瞄示例

select a from t where a between 1001 and 9000

select a from t where a between 101 and 90000

其執i/o資訊如下:

表't'。掃瞄計數1,邏輯讀取234次,物理讀取0 次,預讀0 次,lob 邏輯讀取0 次,lob 物理讀取0 次,lob 預讀0 次。

表't'。掃瞄計數1,邏輯讀取176次,物理讀取0 次,預讀0 次,lob 邏輯讀取0 次,lob 物理讀取0 次,lob 預讀0 次。

如您所預料的,對於第乙個查詢來說,查詢優化器在a列上選擇使用聚集索引來獲取資料,以下是其的查詢計畫:

|--clustered index seek(object:([t].[ta]),

seek:([t].[a] >= convert_implicit(int,[@1],0) and [t].[a] <= convert_implicit(int,[@2],0)) ordered forward)

注意:該計畫中的兩個引數是由自動引數化功能所生成的,當執行該計畫時,@1引數為1001,@2引數為9000.

對於第二個查詢來說,查詢優化器卻選擇了非聚集索引來掃瞄資料,以下其查詢計畫:

|--index scan(object:([t].[tb]), where:([t].[a]>=(101) and [t].[a]<=(90000)))

為 什麼是這樣呢?注意第乙個查詢選擇的記錄數有8千行(相對於10萬行資料而言),對於聚集索引來說,選擇度為表的8%,約230個資料頁,而第二查詢選擇 的記錄數有89000行,選擇度為表的約90%,若使用聚集索引來讀取89000行資料時,則需要讀2500個資料頁.通過比較,非聚集索引僅需要讀取 174個頁面,查詢優化器選擇此計畫,大大減少了i/o操作.

帶書籤查詢的查詢與掃瞄示例

select x from t where b between 101 and 200

select x from t where b between 1001 and 2000

對 於上述的兩個查詢而言,可以通過聚集索引直接掃瞄然後在列b上應用謂詞,或者使用非聚集索引tb在列b上執行索引查詢,然後在聚集索引上執行書籤查詢來讀 取滿足x列值的行.(注意:書籤查詢採用的i/o開銷比較大的方式是隨機讀.)對於查詢的選擇度高的書籤查詢,則是值得的.

以下是第乙個包含書籤查詢的查詢計畫(僅需要讀取100行):

|--nested loops(inner join, outer references:([t].[a], [expr1005]) ...)

|--index seek(object:([t].[tb]), seek:([t].[b] >= (101) and [t].[b] <= (200)) ...)

|--clustered index seek(object:([t].[ta]), seek:([t].[a]=[t].[a]) lookup ...)

而第二個查詢則讀取1000行,對於表而言,僅有1%.查詢優化器由此推出,執行1000次的隨機讀要比執行2800次的順序讀的開銷要大得多,第二個查詢的計畫如下:

|--clustered index scan(object:([t].[ta]), where:([t].[b]>=(1001) and [t].[b]<=(2000)))

源文出處:

A 演算法介紹及其使用舉例

1 a 演算法 a 演算法在人工智慧中是一種典型的啟發式搜尋演算法,啟發中的估價是用估價函式表示的 其中f n 是節點n的估價函式,g n 表示實際狀態空間中從初始節點到n節點的實際代價,h n 是從n到目標節點最佳路徑的估計代價。另外定義h n 為n到目標節點最佳路徑的實際值。如果h n h n ...

HTML簡單介紹及舉例

超文字標記語言 hyper text markup language,簡稱html 是為 網頁建立和其他可在網頁瀏覽器中看到的資訊 設計的一種標記語言。html被用來結構化資訊,也可用來在一定程度上描寫敘述文件的外觀和語義。它是通向web技術世界的鑰匙。1 html 簡單介紹 html是用來描寫敘述...

MySQL建立索引,各種索引的建立及舉例

本文介紹在mysql中建立表的索引,包含建立普通索引,唯一索引,主鍵索引,全文索引,多列索引等,並舉了例子。假設建立乙個zaho user表 create table zaho user u id int 11 not null auto increment,insert time timestam...