DB索引 索引覆蓋 索引優化

2022-05-07 12:33:12 字數 3484 閱讀 2306

###########索引###########

@see

聚集索引(clustered index):聚集索引決定資料在磁碟上的物理排序,乙個表只能有乙個聚集索引,一般用primary key來約束。

舉例:t_user場景中,uid上的索引。

非聚集索引(non-clustered index):它並不決定資料在磁碟上的物理排序,索引上只包含被建立索引的資料,以及乙個行定位符row-locator,這個行定位符,可以理解為乙個聚集索引物理排序的指標,通過這個指標,可以找到行資料。

舉例,查詢年輕mm的業務需求:

select uid from t_user where age > 18 and age < 26;

age上建立的索引,就是非聚集索引。

聯合索引:多個欄位上建立的索引,能夠加速複核查詢條件的檢索

舉例,登入業務需求:

select uid, login_time from t_user where 

login_name=? and passwd=?

可以建立(login_name, passwd)的聯合索引。

聯合索引能夠滿足最左側查詢需求,例如(a, b, c)三列的聯合索引,能夠加速a | (a, b) | (a, b, c) 三組查詢需求。

這也就是為何不建立(passwd, login_name)這樣聯合索引的原因,業務上幾乎沒有passwd的單條件查詢需求,而有很多login_name的單條件查詢需求。

提問

select uid, login_time from t_user where

passwd=? and login_name=?

能否命中(login_name, passwd)這個聯合索引?

回答:可以,最左側查詢需求,並不是指sql語句的寫法必須滿足索引的順序(這是很多朋友的誤解)

索引覆蓋:被查詢的列,資料能從索引中取得,而不用通過行定位符row-locator再到row上獲取,即「被查詢列要被所建的索引覆蓋」,這能夠加速查詢速度。

###########索引優化############

@see

舉例,登入業務需求:

select uid, login_time from t_user where

login_name=? and passwd=?

可以建立(login_name, passwd, login_time)的聯合索引,由於login_time已經建立在索引中了,被查詢的uid和login_time就不用去row上獲取資料了,從而加速查詢。

末了多說一句,登入這個業務場景,login_name具備唯一性,建這個單列索引就好。

假設訂單業務表結構為:

order(oid, date, uid, status, money, time, …)

其中:oid,訂單id,主鍵

date,下單日期,有普通索引,管理後台經常按照date查詢

uid,使用者id,有普通索引,使用者查詢自己訂單

status,訂單狀態,有普通索引,管理後台經常按照status查詢

money/time,訂單金額/時間,被查詢字段,無索引

…假設訂單有三種狀態:0已下單,1已支付,2已完成

業務需求,查詢未完成的訂單,哪個sql更快呢?

select * from order where status!=2

select * from order where status=0 or status=1

select * from order where status in (0,1)

select * from order where status=0

union all

select * from order where status=1

結論:方案1最慢,方案2,3,4都能命中索引

但是...

一:union all 肯定是能夠命中索引的

select * from order where status=0

union all

select * from order where status=1

說明:直接告訴mysql怎麼做,mysql耗費的cpu最少

程式設計師並不經常這麼寫sql(union all)

二:簡單的in能夠命中索引

select * from order where status in (0,1)

說明:讓mysql思考,查詢優化耗費的cpu比union all多,但可以忽略不計

程式設計師最常這麼寫sql(in),這個例子,最建議這麼寫

三:對於or,新版的mysql能夠命中索引

select * from order where status=0 or status=1

說明:讓mysql思考,查詢優化耗費的cpu比in多,別把負擔交給mysql

不建議程式設計師頻繁用or,不是所有的or都命中索引

對於老版本的mysql,建議查詢分析下

四、對於!=,負向查詢肯定不能命中索引

select * from order where status!=2

說明:全表掃瞄,效率最低,所有方案中最慢

禁止使用負向查詢。使用負向查詢時,一定要帶上其他可以過濾大量資料的正向查詢條件,這樣配合使用負向查詢是可以的。

舉例:select oid from t_order where uid=123 and status != 1;

訂單表5000w資料,但uid=123就會迅速的將資料量過濾到很少的級別(uid建立了索引),此時再接上乙個負向的查詢條件就無所謂了,掃瞄的行數本身就會很少。

但如果要查詢所有已完成訂單之外的訂單:

select oid from t_order where status != 1;

這就掛了,立馬cpu100%,status索引會失效,負向查詢導致全表掃瞄。

五、其他方案

select * from order where status < 2

這個具體的例子中,確實快,但是:

這個例子只舉了3個狀態,實際業務不止這3個狀態,並且狀態的「值」正好滿足偏序關係,萬一是查其他狀態呢,sql不宜依賴於列舉的值,方案不通用

這個sql可讀性差,可理解性差,可維護性差,強烈不推薦

MySQL 索引 覆蓋索引

1.什麼是覆蓋索引?概念 查詢語句中所需要的列在索引中,這樣查詢結果在索引的資料結構中查詢即可拿到結果。附加解釋 2.形成覆蓋索引的條件索引分為多種型別,從資料結構上分為 二叉樹 紅黑樹 hash索引 b tree索引,b tree mysql使用的儲存結構 索引的實現可以使用多種資料結構,這裡使用...

mysql 優化(4)索引覆蓋和最優索引

索引覆蓋 很重要的 乙個概念 就是在索引上查詢!如果查詢的列恰好是索引的一部分,那麼查詢只需要在索引檔案上進行 不需要回行到磁碟再找資料.這種查詢速度非常快,稱為 索引覆蓋 非聚促索引 索引檔案對應了資料要回行 浪費掉了時間 索引和資料區別 索引是高效組織起來的樹 節點 查詢樹葉 結構更優於資料 索...

mysql索引 之覆蓋索引

今天參考了 高效能mysql 與幾篇博文,總結一下我個人的對覆蓋索引的理解。首先,覆蓋索引並不是一種新的資料結構,它的意思是在查詢的時候,利用到的索引已經完全包含需要查詢欄位的情況,在這種情況下,查詢結果直接就是索引的值,並不需要再利用索引回表查詢了。繼續拿sakila資料庫 mysql安裝好後自帶...