[MySQL优化案例]系列 — 典型性索引引发CPU负载飙升问题

收到一个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都还好的话,这种情况下,首先想到的一定是索引问题,十有八九错不了。

--------------------------------------分割线--------------------------------------

知数堂 (http://zhishuedu.com)培训是由资深MySQL专家叶金荣、吴炳锡联合推出的专业优质培训品牌,主要有MySQL DBA实战优化和Python运维开发课程,是业内最有良心、最有品质的培训课程。

本文出自 “老叶茶馆” 博客,请务必保留此出处http://imysql.blog.51cto.com/1540006/1879883

时间: 2024-08-06 04:39:42

[MySQL优化案例]系列 — 典型性索引引发CPU负载飙升问题的相关文章

[MySQL优化案例]系列 — RAND()优化

众所周知,在MySQL中,如果直接 ORDER BY RAND() 的话,效率非常差,因为会多次执行.事实上,如果等值查询也是用 RAND() 的话也如此,我们先来看看下面这几个SQL的不同执行计划和执行耗时. 首先,看下建表DDL,这是一个没有显式自增主键的InnoDB表: [[email protected]]> show create table t_innodb_random\G *************************** 1. row *******************

mysql优化案例

MySQL优化案例 Mysql5.1大表分区效率测试 Mysql5.1大表分区效率测试MySQL | add at 2009-03-27 12:29:31 by PConline | view:60, comment:0 mysql5.1开始支持数据表分区了,原来的分表可以不用了,分表的不足在于多表查询不方便.呵呵,下面来简单测试下表分区的查询效率. 1.用来测试的数据为discuz论坛的数据库,表为cdb_posts表,数据量为1500多万条mysql> select count(*) fro

Mysql优化之创建高性能索引(一)

1.索引基础 索引对于良好的性能非常关键.尤其是当表中的数据量越来越大时,索引对性能的影响愈发重要.但是不恰当的索引随着数据量的增加,也会使整个数据库的性能下降. 举个例子: select a from b where id = 5; 如果在id上建立索引,则Mysql会使用该索引找到id为5的行,也就是说,Mysql现在索引按值进行查找,然后返回所有包含该值的数据行.索引也可以包含一列或者多列,列的顺序也十分重要,因为Mysql只能高效地使用索引的最左前缀列. 索引优化应该是查询性能优化最有效

mysql优化实战(explain && 索引)

实验环境: 1.sql工具:Navicat 2.sql数据库,使用openstack数据库作为示例 一.mysql索引查询 show index from instances 结果字段解释: Table:数据库表名 Non_unique:索引不能包括重复词,则为0.可以,则为1. Key_name:索引的名称. 索引中的列序列号,从1开始. 列名称 列以什么方式存储在索引中.在MySQL中,有值'A'(升序)或NULL(无分类). 索引中唯一值的数目的估计值.通过运行ANALYZE TABLE或

MySQL 优化之 index_merge (索引合并)

深入理解 index merge 是使用索引进行优化的重要基础之一.理解了 index merge 技术,我们才知道应该如何在表上建立索引. 1. 为什么会有index merge 我们的 where 中可能有多个条件(或者join)涉及到多个字段,它们之间进行 AND 或者 OR,那么此时就有可能会使用到 index merge 技术.index merge 技术如果简单的说,其实就是:对多个索引分别进行条件扫描,然后将它们各自的结果进行合并(intersect/union). MySQL5.

MySQL 优化之 index merge(索引合并)

MySQL5.0之前,一条语句中一个表只能使用一个索引,无法同时使用多个索引.但是从5.1开始,引入了 index merge 优化技术,对同一个表可以使用多个索引.理解了 index merge 技术,我们才知道应该如何在表上建立索引. 相关文档:http://dev.mysql.com/doc/refman/5.6/en/index-merge-optimization.html (注意该文档中说的有几处错误) The Index Merge method is used to retrie

SQL优化案例分享--联合索引

下面这个SQL如何优化: desc select count(*) as total from Art_Person a, Art_Works b where a.PersonCode=b.PersonCode; +----+-------------+-------+-------+---------------+------------+---------+---------------------+--------+-------------+ | id | select_type | t

MySQL优化器不使用索引的情况

优化器选择不适用索引的情况 有时候,有乎其并没有选择索引而去查找数据,而是通过扫描聚集索引,也就是直接进行全表的扫描来得到数据.这种情况多发生于范围查找.JOIN链接操作等情况.例如 SELECT * FROM orderdetails WHERE orderid>10000 and orderid<102000; 通过SHOW INDEX FROM orderdetails可以看到 可以看到orderdetails有(orderID,ProductID)的联合主键.此外还有对于列OrderI

mysql优化 之 group by索引松散扫描和紧凑扫描

group by语句利用B+tree索引扫描时分为松散扫描.紧凑扫描两种情况: Loose Index Scan(松散扫描)就是只需要对索引扫描时取出很小一部分键值就能完成整个sql所需数据的扫描,在where条件含有范围谓词或者无条件.sql语句利用索引就能完成查询的才能使用上松散扫描,用上松散索引扫描的有如下几种类型的语句: 表t1有c1,c2,c3,c4四个字段,index为(c1,c2,c3) SELECT c1, c2 FROM t1 GROUP BY c1, c2;    SELEC