為什麼狀態少的字段不能建索引

2021-07-13 22:47:06 字數 3394 閱讀 7501

此處以sqlserver為示例做演示。

大多教科書和前輩們都說狀態少的字段不要建索引,由此帶來的開銷還不如不建索引,但是這句話有多少人真的知道,或者說有多少人真的對此有比較深刻的理解,而不是聽別人道聽途說。這樣記得快,忘記的也不慢。這篇我來分析一下這句話到底有幾個意思。

一:現象

首先我們還是用測試資料來發現問題,我先建立乙個person,有5個字段,建表sql如下:

drop

table

dbo.person

create

table person(id int

primary

keyidentity,name varchar(900),age int,email varchar(20),isman int)--

在isman欄位建立非聚集索引(0:女 1:男)

create

index idx_isman on

dbo.person(isman)

declare

@chas

int=

0

while

@ch<=

100000

begin

insert

into

dbo.person(name,age,email,isman)

values

(

replicate(char(@ch),50),

@ch,

cast(cast(rand()*

1000000000as

int) as

varchar(10))+

'qq.com',

@ch%

2)

set@ch

=@ch

+1

end

通過上面的sql可以發現表中有5個字段,id為聚集索引,isman為非聚集索引,isman也就是兩種狀態(0,1),並且插入10w條記錄,截圖如下:

sql都做完了,接下來要做的事情就是查詢下: isman=1的記錄,如下圖:

哥明明是在isman上做資料檢索的,怎麼就變成 「聚集索引掃瞄」了?這他麼的什麼意思嘛,居然不走我的「idx_isman」索引,

卻走他麼的「聚集索引(pk__person__3214ec276ef57b66)」。。同時也看到上面的」邏輯讀取」為521。。說明在記憶體中走了521個資料頁。

但是我不服呀。。。我一定要讓執行計畫走我的索引。。。辦法就是強制指定。。。如下圖。

看到上面的圖,你是不是已經瘋了。。。老子才撈5w的資料,你給我走了10w多次資料頁。。。這麼說1條記錄要走兩個資料頁。。。而掃瞄聚集

索引才走521個資料頁,相差200倍。。。難怪執行計畫打死也不走「idx_isman」這條索引。。。要是這樣走了人家還不拿刀捅了sqlserver麼???

二:分析原因

現在很生氣,整個人都不好了,為什麼會這樣?為了找出問題,我們還得看資料頁。

通過上面的三個圖,大概可以看到,10w條資料用了697資料頁,其中聚集索引有521個,非聚集索引為176個,這也說明了上面的」聚集索引掃瞄「走

遍了它自己所有的資料頁來才撈出資料,同時還發現這兩個索引都有乙個共同特徵就是,只有乙個根節點(indexlevel=1)和無數個(indexlevel=0)

葉子節點,然後我腦子裡面就有一幅圖出來了。。。

上面就是我構思出來的圖,這個專業一點的名字叫做書籤查詢。。。我們通過建立」idx_isman「索引後,就會構建右半圖的b樹結構,其中索引記錄

會存放兩個值,乙個是索引值isman和乙個聚集索引值id,如果你不相信的話,可以通過dbcc page去探索"idx_isman"的索引頁,你也可以通過

dbcc show_statistics 去檢視,如圖:

然後引擎通過「idx_isman「掃瞄後,拿到了key值,但是非常可惜,我是select * 的,所以必須還要噴出記錄中的name,emai等l欄位,但是

」index_isman"中並沒有儲存這幾個字段,所以必須通過key去」聚集索引「的b樹中去找。。。最後通過」聚集索引「的b樹找到了目標記錄,這也

就是所謂的執行計畫中的」鍵查詢「,然後噴出」name,email「等字段。。。。問題就在這裡。。。因為我這樣來回的蹦躂蹦躂。。。造成了找出

完整的乙個記錄,需要蹦躂2-3次資料頁。。。具體的尋找記錄,可參考圖中的」紫色線條「,最後也就造成了10w多次蹦躂。。。

三:啟示

那這個例子給我們什麼啟示呢???仔細想想你就知道。。。使用非聚集索引,千萬不要撈取過多的資料。。。因為過多的資料會造成在多個

b樹中來回的蹦躂。。。想要做到撈取資料較少,就必須在高唯一性的字段上建立索引,這樣的話在非聚集索引b樹中符合的資料相對較少,也就

減少了我蹦躂到」主鍵索引「的b樹次數。。。這樣的話來回蹦躂的次數遠遠比」聚集索引「掃瞄來的實惠,對不對。。。

所以結論出來了:必須在唯一性較高的字段上建立非聚集索引。

為什麼重複值高的字段不能建索引(比如性別欄位等

結論 以innodb為例 a 非聚簇索引儲存了對主鍵的引用,如果select欄位不在非聚簇索引內,就需要跳到主鍵索引 上圖中從右邊的索引樹跳到左邊的索引樹 再獲取select字段值 b 如果非聚簇索引值重複率高,那麼查詢時就會大量出現上圖中從右邊跳到左邊的情況,導致整個流程很慢 c 如果where值...

為什麼重複值高的字段不能建索引(比如性別欄位等

結論 以innodb為例 a 非聚簇索引儲存了對主鍵的引用,如果select欄位不在非聚簇索引內,就需要跳到主鍵索引 上圖中從右邊的索引樹跳到左邊的索引樹 再獲取select字段值 b 如果非聚簇索引值重複率高,那麼查詢時就會大量出現上圖中從右邊跳到左邊的情況,導致整個流程很慢 c 如果where值...

為什麼要建聯合索引?

為什麼要使用聯合索引 減少開銷。建乙個聯合索引 col1,col2,col3 實際相當於建了 col1 col1,col2 col1,col2,col3 三個索引。每多乙個索引,都會增加寫操作的開銷和磁碟空間的開銷。對於大量資料的表,使用聯合索引會大大的減少開銷!覆蓋索引。對聯合索引 col1,co...