去掉不该连接的表

php中文网
发布: 2016-06-07 17:36:49
原创
1044人浏览过

数据库收到报警,负载飙至60,上去一看,cpu飙至3000%,32个核心所剩无几!第一反应,sql语句卡住了。登录mysql,showprocesslist,发现大量重复的sql语句SELECT

数据库收到报警,负载飙至60,上去一看,cpu飙至3000%,32个核心所剩无几!

第一反应,sql语句卡住了。

登录mysql,show processlist,发现大量重复的sql语句

SELECT cv.filter_value_id,cv.filter_id,cv.value,COUNT(1) quantity FROM e_category_filter_value AS cv INNER JOIN e_product_to_filter_value AS p_v ON cv.filter_value_id=p_v.filter_value_id INNER JOIN products AS p ON p_v.products_id = p.products_id INNER JOIN products_to_categories AS p_c ON p_c.products_id=p_v.products_id WHERE cv.filter_id IN(575,576,568,572,569,570,571,573,574) GROUP BY cv.filter_value_id;

已经有人反应网站开始打不开,为了尽快解决问题,,使用自己写的快速杀连接脚本杀掉这些sql语句.脚本大致可以参考sql语句

SELECT * FROM information_schema.processlist WHERE TIME >=5 AND USER LIKE 'banggood%' AND (state LIKE 'Copying%' OR state LIKE 'Sending%' OR state LIKE 'Sorting%'

连续杀了几次,发现cpu稳定,网站也趋于稳定!

接下来着手优化这条sql语句!

第一步,找到对应的开发人员,了解大致作用。

第二步,explian

mysql> explain SELECT SQL_NO_CACHE cv.filter_value_id,cv.filter_id,cv.value,COUNT(1) quantity FROM e_category_filter_value AS cv INNER JOIN e_product_to_filter_value AS p_v ON cv.filter_value_id=p_v.filter_value_id INNER JOIN products AS p ON p_v.products_id = p.products_id INNER JOIN products_to_categories AS p_c ON p_c.products_id=p_v.products_id WHERE cv.filter_id IN(575,576,568,572,569,570,571,573,574) GROUP BY cv.filter_value_id; +----+-------------+-------+--------+---------------------------------+-------------+---------+------------------------------+-------+----------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------------------------+-------------+---------+------------------------------+-------+----------------------------------------------+ | 1 | SIMPLE | p_c | index | PRIMARY | PRIMARY | 8 | NULL | 98109 | Using index; Using temporary; Using filesort | | 1 | SIMPLE | p | eq_ref | PRIMARY | PRIMARY | 4 | banggood.p_c.products_id | 1 | Using index | | 1 | SIMPLE | p_v | ref | products_id,ix_eptfv_fvid_proid | products_id | 4 | banggood.p_c.products_id | 16 | | | 1 | SIMPLE | cv | eq_ref | PRIMARY,filter_id | PRIMARY | 4 | banggood.p_v.filter_value_id | 1 | Using where | +----+-------------+-------+--------+---------------------------------+-------------+---------+------------------------------+-------+----------------------------------------------+

发现并没有使用索引cv.filter_id(该索引是存在的),而是选择了p_c表的主键,导致了全索引扫描,大量损耗cpu。

第三步,尝试使用force index

mysql> EXPLAIN -> SELECT SQL_NO_CACHE cv.filter_value_id,cv.filter_id,cv.value,COUNT(1) quantity -> FROM e_category_filter_value AS cv FORCE INDEX(filter_id) -> INNER JOIN e_product_to_filter_value AS p_v ON cv.filter_value_id=p_v.filter_value_id -> INNER JOIN products AS p ON p_v.products_id = p.products_id -> INNER JOIN products_to_categories AS p_c ON p_c.products_id=p_v.products_id -> WHERE cv.filter_id IN(575,576,568,572,569,570,571,573,574) -> GROUP BY cv.filter_value_id; +----+-------------+-------+--------+---------------------------------+---------------------+---------+-----------------------------+------+----------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------------------------+---------------------+---------+-----------------------------+------+----------------------------------------------+ | 1 | SIMPLE | cv | range | filter_id | filter_id | 4 | NULL | 75 | Using where; Using temporary; Using filesort | | 1 | SIMPLE | p_v | ref | products_id,ix_eptfv_fvid_proid | ix_eptfv_fvid_proid | 4 | banggood.cv.filter_value_id | 1495 | Using index | | 1 | SIMPLE | p_c | ref | PRIMARY | PRIMARY | 4 | banggood.p_v.products_id | 981 | Using index | | 1 | SIMPLE | p | eq_ref | PRIMARY | PRIMARY | 4 | banggood.p_c.products_id | 1 | Using where; Using index | +----+-------------+-------+--------+---------------------------------+---------------------+---------+-----------------------------+------+----------------------------------------------+

对比两次执行时间,为使用force index时,执行需要2s;使用后,执行时间变为0.03s。

你以为这次优化就这样结束了,那就和我给的题目不符了!

淘特微信宝
淘特微信宝

淘特微信宝是淘特CMS团队最新研制的微信公众平台管理工具包,该产品提供一个后台管理多个微信公众号功能,可以一站式管理多个微信公众号的自动回复消息、自定义菜单等功能,通过后台可视化操作免去微信接口程序开发的繁锁工作,令不懂程序的人也能灵活管理微信公众号。

淘特微信宝 0
查看详情 淘特微信宝

第四部:

仔细观察这个sql语句,发现where里面和select子句里面都么有设计到

INNER JOIN products AS p ON p_v.products_id = p.products_id INNER JOIN products_to_categories AS p_c ON p_c.products_id=p_v.products_id

这两个连表子句的任何参数,询问开发,发现需要和products表做连表过滤,因为可能在e_category_filter_value表中存在的products_id,但是可能在products表中不存在。而至于products_to_categories表(产品对类别表,一个产品对应了多个类别,是一个可以将结果集放大非常多倍的表),他找不到加上的理由。

现在去掉products_to_categories表

mysql> EXPLAIN -> SELECT SQL_NO_CACHE cv.filter_value_id,cv.filter_id,cv.value,COUNT(1) quantity -> FROM e_category_filter_value AS cv -> INNER JOIN e_product_to_filter_value AS p_v ON cv.filter_value_id=p_v.filter_value_id -> INNER JOIN products AS p ON p_v.products_id = p.products_id -> WHERE cv.filter_id IN(575,576,568,572,569,570,571,573,574) -> GROUP BY cv.filter_value_id; +----+-------------+-------+--------+---------------------------------+---------------------+---------+-----------------------------+------+----------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------------------------+---------------------+---------+-----------------------------+------+----------------------------------------------+ | 1 | SIMPLE | cv | range | PRIMARY,filter_id | filter_id | 4 | NULL | 75 | Using where; Using temporary; Using filesort | | 1 | SIMPLE | p_v | ref | products_id,ix_eptfv_fvid_proid | ix_eptfv_fvid_proid | 4 | banggood.cv.filter_value_id | 1495 | Using index | | 1 | SIMPLE | p | eq_ref | PRIMARY | PRIMARY | 4 | banggood.p_v.products_id | 1 | Using index | +----+-------------+-------+--------+---------------------------------+---------------------+---------+-----------------------------+------+----------------------------------------------+ 3 rows in set (0.00 sec)

发现索引使用正确,再次执行,发现执行时间变为0.03s。


总结:1.尽量不要连接一些可有可无的表,这个例子就是血的教训

2.不要太相信mysql的索引使用,有的时候需要自己借助于force index命令来进行调优!

本文出自 “原下” 博客,请务必保留此出处

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号