最近在寫一些資料統計的面板,裡面有sql對錶資料的聚合統計,我的主表現在有100來萬的資料,其間看了很多資料。記錄一下sql索引的優化過程. sql 如下,只有乙個連表查詢,再加上函式聚合出結果
select
count(if
(b.severity =1,
true
,null
)) severityallnum,
count(if
(b.severity =2,
true
,null
)) importanceallnum,
count(if
(b.severity =
1and timestampdiff(
minute
, b.
time
, b.solve_time)
<=60,
true
,null
)) severitydonenum,
count(if
(b.severity =
2and timestampdiff(
minute
, b.
time
, b.solve_time)
<=
240,
true
,null))
importancedonenum
from
(select a.
time
, a.solve_time, a.severity
from alarm_log a
left
(alarm_business_id)
where
a.channel =
and a.
statusin(
2,3,
4)and a.
time
>=
'2019-12-30 00:00:00'
and a.
time
<=
'2020-01-03 23:59:59'
group
by alai.alarm_business_id
order
bynull
) b
我們看一下沒有任何索引這個的執行計畫,表a的rows函式是100多w,type = all,屬於全表掃瞄了,這樣執行sql會非常慢。我們急需索引來篩選不需要掃瞄的行。
最左字首匹配原則,建立索引我們需要第乙個要想到的,mysql會一直向右匹配直到遇到範圍查詢(>、 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調整。 從這裡也建議了最好不要用單列索引
但是如何建立乙個多列索引呢,多個列名怎麼做排列?這裡引出列區分度
,簡單的說就是每一列的 所有不重複資料 / 總條數的比例,按照上面的sql,我們用另一條sql計算一下where/select/group by 那些列的區分度
select
count
(distinct alarm_business_id)
/count(*
),count
(distinct
time)/
count(*
),count
(distinct solve_time)
/count(*
),count
(distinct channel)
/count(*
),count
(distinct
status)/
count(*
),count
(distinct severity)
/count(*
)from alarm_log;
我們可以看到 alarm_business_id,time 區分度是比較高的。它們可以放在索引的前面,讓mysql引擎層篩選出更多的行,但是最左字首匹配原則會匹配到範圍查詢
為止,所以我們更多把 時間字段放在索引最後。下面是我的第一版索引
create
index alarm_log_index
on alarm_log (channel,
status
, severity, alarm_business_id,
time
, solve_time)
;
我們看看索引掃瞄了多少行,58w多,差不多是總數的一半。說明索引建立的還是有效果的,但是我們的索引優化還沒有終結。
上圖中extra列中有乙個use index,這是啥意思?這裡提到了覆蓋索引
的概念,我們首先要知道,主鍵是乙個聚簇索引,它儲存了這一行所有列的資料,所以當我們根據id 去查詢一條資料時,我們取出來的列資料是從索引中直接拉取出來的,無需回表查詢,而回表的意思就是拿著主鍵id重新從資料庫查一遍我們需要的列資料,而非主鍵列的索引 叫非聚簇索引,它只持有主鍵的id,所以當你用非聚簇索引查詢出來的資料 其實經過了兩次io – 第一次查詢出條件行的id,第二次根據id查詢出所需要的列資料(回表)。
那有個疑問了,非聚簇索引就一定只能回表才能查詢出所有資料嗎?覆蓋索引
就解決了我們的難題,我們把 where 和 select的列全部加到索引中,並且執行計畫中 extra列 顯示use index,就說明覆蓋索引開始生效。試想,如果索引的葉子結點已經包含了要查詢的資料,我們何必要多做一次回表查詢.
索引優化沒有乙個固定的模板,一切都是根據業務實際嘗試出來的結果,有些時候你認為mysql應該走這個索引,但是實際上卻走的全表掃瞄,很大原因是因為mysql執行計畫認為你的資料量還不夠大,走索引還不如全表掃瞄快,換言之,理論上覆蓋索引已經是索引優化的理想態,因為它全部都是走索引取資料嘛,但是實際情況你可以繼續減少掃瞄行來提高查詢效能,接下來就介紹索引下推,這應該是mysql 5.6之後出來的特性。
我們來看看 沒有索引下推和有索引下推 ,一條sql是怎麼篩選資料的。
索引下推
貌似優化了 以前最左字首匹配的侷限,在引擎層可以過濾更多的行,直接的好處就是減少了回表查詢和server層額外的where過濾。基於這個特性,我優化了一下我的索引,把區分度最高的time欄位放第乙個,這樣引擎層能一下篩選掉大部分資料,而且有了索引下推,能保證後面字段不會因為範圍查詢而用不上索引。
create
index alarm_log_index
on alarm_log (
time
, alarm_business_id, solve_time, metric_name, severity, major_type, channel)
;
可以看到掃瞄的行數 下降到15w左右,效果顯著!extra列 顯示use index condition
,說明索引下推開始生效。
MySql索引優化實踐
mysql 查詢官方預設底層索引這一頁大小 show global status like innodb page size variable name value innodb page size 16384 位元組0 1024 16k 如果乙個節點設定為 bigint 的話mysql 預設是8個...
mysql索引實踐 MySQL索引實踐
資料庫索引本質上是一種資料結構 儲存結構 演算法 目的是為了加快資料檢索速度。1 索引的型別 待完善 主鍵索引 給表設定主鍵,這個表就擁有主鍵索引。唯一索引 unique 普通索引 增加某個欄位的索引,比如使用者表根據使用者名稱查詢。組合索引 使用多個字段建立索引,遵循最左原則,比如建立索引 col...
mysql 優化 聚集索引 mysql 索引優化
一.聚集索引 clustered index innodb預設依據主鍵列聚集,myisam不使用 特點 b樹每個葉子包含實際資料行,資料按照索引順序地儲存在物理頁上。優點 1.範圍查詢,獲取指定id的全部資料只需從磁碟讀取少量資料頁 如果不使用聚集索引,每條資料可能引起一次磁碟io。2.由於索引和資...