結論區分度低的索引到底會帶來哪方面的影響?
#資料量約700w
create table `order` (
`orderid` varchar(32) not null comment '訂單編號',
`type` char(1) default '0' comment '訂單型別:0 流量訂單,1 話費訂單',
`caller` varchar(16) not null comment '手機號碼',
`status` smallint(6) not null default '0' comment '-1下單失敗、0初始、1待支付、2支付超時、3支付成功、4充值中、5充值成功、6充值失敗 7充值超時 8退款中 9退款失敗 10退款成功',
`ordertime` datetime default current_timestamp comment '訂單下單的時間',
`biztype` varchar(6) default null comment '應用下業務標識',
primary key (`orderid`),
key `index_orderid` (`orderid`),
key `index_status` (`status`),
key `index_caller` (`caller`),
key `index_ordertime` (`ordertime`),
key `index_type` (`type`)
) engine=innodb default charset=utf8 row_format=compact comment='訂單表';
複製**
#耗時約25s
select
count( * ) as col_0_0_
from
`order` orderentit0_
where
1 = 1
and orderentit0_.type = '0'
and status = '5'
and ordertime >= '2017-08-01 16:17:00'
and ordertime <= '2017-08-30 16:17:00';
複製**
從上面的ddl我們可以看到能利用上的索引欄位有:
使用explain命令來進行分析
可以看到利用了status,type兩個欄位的索引,使用了索引合併(同時走兩個索引,取交集)
這邊有幾個疑問?
show index from order
重點關注cardinality字段,翻譯為基數,可以理解為該索引字段不同結果的總數,用於粗略判斷索引區分度(數值越大越好)
可以判斷type,status兩個欄位的索引的區分度十分的低
所以通過這兩個索引欄位會取出一大堆資料,再一一對ordertime欄位進行過濾,效率自然就低了
我們使用force index ( index_ordertime ) 來強制走ordertime索引
explain
select
count( * ) as col_0_0_
from
`order` orderentit0_ force
index ( index_ordertime )
where
1 = 1
and orderentit0_.type = '0'
andstatus = '5'
and ordertime >= '2017-08-01 16:17:00'
and ordertime <= '2017-08-30 16:17:00'
;複製**
來看explain分析結果
通過強制走ordertime索引方式,耗時約4s
結合之前的explain結果做個對比
索引type
keyrows
type,status
index_merge
index_type,index_status
58wordertime
range
index_ordertime
96w 可以看到因為sql優化器判斷通過走合併index_status和index_type比走index_ordertime索引需要檢索的行數少,所以選擇了走索引合併
# 實際結果約47w,執行時間0.4s
select
count( * ) as col_0_0_
from
`order` orderentit0_ force index ( index_ordertime )
where
1 = 1
and ordertime >= '2017-08-01 16:17:00'
and ordertime <= '2017-08-30 16:17:00'
# 實際結果約23w,執行時間8s
select
count( * ) as col_0_0_
from
`order` orderentit0_
where
1 = 1
and orderentit0_.type = '0'
and status = '5'
複製**
至此兩個問題解釋完畢,鼓掌鼓掌?
但是又帶來第三個問題....
1.索引合併,覆蓋
#23w,約3.5s
select count( * ) as col_0_0_
from `order` orderentit0_
where 1 = 1
and orderentit0_.type = '0'
and status = '5'
explain:
index_merge index_status,index_type null 587752
2.ordertime索引,覆蓋
#47w,約0.8s
select
count( * ) as col_0_0_
from
`order` orderentit0_
where
1 = 1
and ordertime >= '2017-08-01 16:17:00'
and ordertime <= '2017-08-30 16:17:00'
explain:
range index_ordertime null 963112
3.索引合併,非覆蓋
#23w,約22s
from `order` orderentit0_
where 1=1
and orderentit0_.type = '0'
and status = '5'
explain:
同14.ordertime索引,非覆蓋
#47w,約4s
select
from
`order` orderentit0_
force index ( index_ordertime )
where
1 = 1
and ordertime >= '2017-08-01 16:17:00'
and ordertime <= '2017-08-30 16:17:00'
explain:
同25.status索引,覆蓋
#37w,約0.3s
select count( * ) as col_0_0_
from `order` orderentit0_
where 1 = 1
and status = '5'
6.type索引,覆蓋
#400w,約1.7s
select count( * ) as col_0_0_
from `order` orderentit0_
where 1 = 1
and orderentit0_.type = '0'
複製**
猜測?:
由於type欄位索引區分度太低,導致多餘的磁碟io時間
對ordertime索引的查詢型別為range,優先順序較低
本人水平有限,在此丟擲問題,請各位大神賜教
刪除type,status,ordertime索引(前二區分度太低),
新增ordertime,status,type的聯合索引(基於業務需求)
**********===2018-04-09***************===
對於問題三的找到理論依據了
記一次慢查詢引發的事故
首先,測試環境上線新版本,並且通過黑盒測試以及功能測試。然後,我們就上線了新的版本。但是在執行3天後,整個伺服器大部分介面都失效了,基本上都是timeout。檢查伺服器情況 cpu基本上佔滿了。接著查了資料庫狀態,通過mysql命令show processlist 存在大量的waiting for ...
記一次Mongodb聚合查詢 慢查詢簡單分析
記一次mongodb聚合查詢 一 慢查詢 db.public setting detail.aggregate isdir 1,status 1 createtime 執行分析結果 1 fields queryplanner winningplan direction forward rejecte...
記一次sql查詢
效果圖 要查詢出如上圖的效果 知識點.1.多表巢狀查詢.2.輸出查詢結果,group concat函式 3.關聯查詢 select t1.學校,case when t1.年級 2017 then 1年級 when t1.年級 2016 then 2年級 when t1.年級 2015 then 3年...