直接切入正题吧:
通常来说,我们看到的慢查询一般还不致于导致挂站,顶多就是应用响应变慢
不过这个恰好今天被我撞见了,一个慢查询把整个网站搞挂了
先看看这个SQL张撒样子:
# Query_time: 70.472013 Lock_time: 0.000078 Rows_sent: 7915203 Rows_examined: 15984089 Rows_affected: 0 # Bytes_sent: 1258414478 use js_sku; SET timestamp=1465850117; SELECT ss_id, ss_sa_id, ss_si_id, ss_av_zid, ss_av_fid, ss_artno, ss_av_zvalue, ss_av_fvalue, ss_av_zpic, ss_av_fpic, ss_number, ss_sales, ss_cprice, ss_price, ss_stock, ss_orderid, ss_status, ss_add_time, ss_lastmodify FROM js_sgoods_sku WHERE ss_si_id = 0 AND ss_status > 0 ORDER BY ss_orderid DESC, ss_av_fid ASC; |
这里贴出来的就是 mysql slow log 的信息,查询时间用了高达 70s!!
看到慢查询我们一般第一反应是这个 语句没有用到索引? 或者是索引不合理么? 那我们会去看看执行计划:
mysql> explain SELECT -> ss_id, ss_sa_id, ss_si_id, ss_av_zid, ss_av_fid, ss_artno, -> ss_av_zvalue, ss_av_fvalue, ss_av_zpic, ss_av_fpic, ss_number, -> ss_sales, ss_cprice, ss_price, ss_stock, ss_orderid, ss_status, -> ss_add_time, ss_lastmodify -> FROM js_sgoods_sku -> WHERE ss_si_id = 0 AND ss_status > 0 -> ORDER BY -> ss_orderid DESC, ss_av_fid ASC; +----+-------------+---------------+------+---------------+----------+---------+-------+---------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------------+------+---------------+----------+---------+-------+---------+-----------------------------+ | 1 | SIMPLE | js_sgoods_sku | ref | ss_si_id | ss_si_id | 4 | const | 9516091 | Using where; Using filesort | +----+-------------+---------------+------+---------------+----------+---------+-------+---------+-----------------------------+ 1 row in set (0.00 sec) |
这个看起来似乎用到了索引,可是为什么扫描到行还是这么多呢? 那我们就去看看表结构了,期望能从中找到点有价值的东西:
我们看到如下可用信息:
KEY `ss_si_id` (`ss_si_id`,`ss_av_zid`,`ss_av_fid`) USING BTREE,
`ss_si_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '对应js_sgoods_info.si_id',
我们看到 索引似乎还能比较能够接受,但是我们看到 这个 ss_si_id 这个字段实际上是 goods_info 表的主键,也就是说它的离散程度应该是很大的,也就是区分度很大。
其实到这一步我们基本上可以认为 是由于我们这个表里边有很多 ss_si_id=0 导致,不过我们可以进一步的来证实我们的猜想:
1. 首先我们可以先确定我们的统计信息没有问题
2. 其次我们再count ss_si_id=0 的这个值有多少数据,来进一步验证我们的猜想。
那么我们先查看以下这个索引的统计信息:
xiean@localhost:js_sku 03:27:42>show index from js_sgoods_sku; +---------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +---------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | js_sgoods_sku | 0 | PRIMARY | 1 | ss_id | A | 18115773 | NULL | NULL | | BTREE | | | | js_sgoods_sku | 1 | ss_si_id | 1 | ss_si_id | A | 1811577 | NULL | NULL | | BTREE | | | | js_sgoods_sku | 1 | ss_si_id | 2 | ss_av_zid | A | 6038591 | NULL | NULL | | BTREE | | | | js_sgoods_sku | 1 | ss_si_id | 3 | ss_av_fid | A | 18115773 | NULL | NULL | | BTREE | | | | js_sgoods_sku | 1 | IDX_001 | 1 | ss_sa_id | A | 3623154 | NULL | NULL | | BTREE | | | +---------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ |