一条慢SQL引发的血案

发表于:2016-7-05 10:23

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:大白的记事本    来源:51Testing软件测试网采编

  直接切入正题吧:
  通常来说,我们看到的慢查询一般还不致于导致挂站,顶多就是应用响应变慢
  不过这个恰好今天被我撞见了,一个慢查询把整个网站搞挂了
  先看看这个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 | | |
+---------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号