欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

分析MySQL中索引引引发的CPU负载飙升的问题

程序员文章站 2024-02-28 14:01:16
收到一个mysql服务器负载告警,上去一看,load average都飙到280多了,用top一看,cpu跑到了336%,不过io和内存的负载并不高,根据经验,应该又是一起...

收到一个mysql服务器负载告警,上去一看,load average都飙到280多了,用top一看,cpu跑到了336%,不过io和内存的负载并不高,根据经验,应该又是一起索引引起的*了。

看下processlist以及slow query情况,发现有一个sql经常出现,执行计划中的扫描记录数看着还可以,单次执行耗时为0.07s,还不算太大。乍一看,可能不是它引发的,但出现频率实在太高,而且执行计划看起来也不够完美:

mysql> explain select count(1) from a , b where a.id = b.video_id and b.state = 1 and b.column_id = '81'\g

*************************** 1. row ***************************
id: 1
select_type: simple
table: b
type: index_merge
possible_keys: columnid_videoid,column_id,state,video_time_stamp,idx_videoid
key: column_id,state
key_len: 4,4
ref: null
rows: 100
extra: using intersect(column_id,state); using where
*************************** 2. row ***************************
id: 1
select_type: simple
table: a
type: eq_ref
possible_keys: primary
key: primary
key_len: 4
ref: b.video_id
rows: 1
extra: using where; using index

再看下该表的索引情况:

mysql> show index from b\g

*************************** 1. row ***************************
table: b
non_unique: 0
key_name: primary
seq_in_index: 1
column_name: id
collation: a
cardinality: 167483
sub_part: null
packed: null
null:
index_type: btree
comment:
index_comment:
*************************** 2. row ***************************
table: b
non_unique: 1
key_name: column_id
seq_in_index: 1
column_name: column_id
collation: a
cardinality: 8374
sub_part: null
packed: null
null:
index_type: btree
comment:
index_comment:
*************************** 3. row ***************************
table: b
non_unique: 1
key_name: state
seq_in_index: 2
column_name: state
collation: a
cardinality: 5
sub_part: null
packed: null
null:
index_type: btree
comment:
index_comment:

可以看到执行计划中,使用的是index merge,效率自然没有用联合索引(也有的叫做覆盖索引)来的好了,而且 state 字段的基数(唯一性)太差,索引效果很差。删掉两个独立索引,修改成联合看看效果如何:

mysql> show index from b;

*************************** 1. row ***************************
table: b
non_unique: 0
key_name: primary
seq_in_index: 1
column_name: id
collation: a
cardinality: 128151
sub_part: null
packed: null
null:
index_type: btree
comment:
index_comment:
*************************** 2. row ***************************
table: b
non_unique: 1
key_name: idx_columnid_state
seq_in_index: 1
column_name: column_id
collation: a
cardinality: 3203
sub_part: null
packed: null
null:
index_type: btree
comment:
index_comment:
*************************** 3. row ***************************
table: b
non_unique: 1
key_name: idx_columnid_state
seq_in_index: 2
column_name: state
collation: a
cardinality: 3463
sub_part: null
packed: null
null:
index_type: btree
comment:
index_comment:

mysql> explain select count(1) from a , b where a.id = b.video_id and b.state = 1 and b.column_id = '81' \g

*************************** 1. row ***************************
id: 1
select_type: simple
table: b
type: ref
possible_keys: columnid_videoid,idx_videoid,idx_columnid_state
key: columnid_videoid
key_len: 4
ref: const
rows: 199
extra: using where
*************************** 2. row ***************************
id: 1
select_type: simple
table: a
type: eq_ref
possible_keys: primary
key: primary
key_len: 4
ref: b.video_id
rows: 1
extra: using where; using index

 可以看到执行计划变成了只用到了 idx_columnid_state 索引,而且 ref 类型也变成了 const,sql执行耗时也从0.07s变成了0.00s,相应的cpu负载也从336%突降到了12%不到。

总结下,从多次历史经验来看,如果cpu负载持续很高,但内存和io都还好的话,这种情况下,首先想到的一定是索引问题,十有八九错不了。