- 1 首先我们找到mysql占比高的进程号PID
top
- 2 根据PID找到mysql的os_thread_id
top -H -p 2559
我们这里可以明显看到有个pid=16815的程序在占用cpu进程 那么我们找到这进行查询的慢sql
这里可以看到是哪个主机连接的信息
SELECt a. USER, a. HOST, a.db, b.thread_os_id, b.thread_id, a.id processlist_id, a.command, a.time, a.state, a.info FROM information_schema. PROCESSLIST a, PERFORMANCE_SCHEMA .threads b WHERe a.id = b.processlist_id AND b.thread_os_id = 16804;
- 我们最终要的是sql 那么执行下面找个就可以找到高id的进程所属的sql
SELECt * FROM PERFORMANCE_SCHEMA.events_statements_current WHERe thread_id = ( SELECt thread_id FROM PERFORMANCE_SCHEMA .threads WHERe thread_os_id = 16804 ) ;
接下来优化sql就行了
这里我们随意找一处比较耗时的sql来做统计
这应该是一位非常懂这块业务的哥们写的 我们来看一下
EXPLAIN SELECt g.* FROM ( SELECt DISTINCT ru.id AS unitId, ru.unit_name AS unitName, ru.create_time, ru.baseid, ru.entid , p.id AS postId, p.post_name AS postName, IFNULL(a.patrolNum, 0) AS patrolNum , IFNULL(ht.hiddenNum, 0) AS hiddenNum, b.postRiskLevel , b.postRiskLevelText, c.unitRiskLevel, c.unitRiskLevelText FROM drh_risk_unit_post rup LEFT JOIN drh_risk_unit ru ON ru.id = rup.risk_unit_id LEFT JOIN ent_post p ON p.id = rup.post_id LEFT JOIN ( SELECt COUNT(1) AS patrolNum, pp.post_id FROM drh_post_patrol pp GROUP BY pp.post_id ) a ON a.post_id = rup.post_id LEFT JOIN ( SELECt COUNT(1) AS hiddenNum, h.post_id FROM drh_hidden h GROUP BY h.post_id ) ht ON ht.post_id = rup.post_id LEFT JOIN ( SELECt llt.*, dt.item_text AS postRiskLevelText FROM ( SELECt ht1.* FROM ( SELECt a.*, rup.risk_unit_id FROM drh_risk_unit_post rup LEFT JOIN ( SELECt MIN(hft.risk_level) AS postRiskLevel, pr.post_id FROM ( SELECt hf.fk_id, MIN(hf.risk_level) AS risk_level FROM drh_post_result_hazar_factors hf GROUP BY hf.fk_id ) hft LEFT JOIN drh_post_result pr ON pr.id = hft.fk_id WHERe pr.post_id IS NOT NULL GROUP BY pr.post_id ) a ON a.post_id = rup.post_id LEFT JOIN drh_risk_unit ru ON ru.id = rup.risk_unit_id WHERe ru.unit_source = '1' ) ht1 UNIOn ALL SELECt ht2.* FROM ( SELECt a.*, rup.risk_unit_id FROM drh_risk_unit_post rup LEFT JOIN ( SELECt MIN(hft.risk_level) AS postRiskLevel, sm.post_id FROM ( SELECt hf.fk_id, MIN(hf.risk_level) AS risk_level FROM drh_post_result_hazar_factors hf GROUP BY hf.fk_id ) hft LEFT JOIN drh_safety_matters sm ON sm.id = hft.fk_id WHERe sm.post_id IS NOT NULL GROUP BY sm.post_id ) a ON a.post_id = rup.post_id LEFT JOIN drh_risk_unit ru ON ru.id = rup.risk_unit_id WHERe ru.unit_source = '2' ) ht2 ) llt LEFT JOIN sys_dict_item dt ON llt.postRiskLevel = dt.item_value LEFT JOIN sys_dict d ON dt.dict_id = d.id WHERe d.dict_code = 'drh_inherent_risk_level' ) b ON b.risk_unit_id = rup.risk_unit_id AND b.post_id = rup.post_id LEFT JOIN ( SELECt tll.*, dt.item_text AS unitRiskLevelText FROM ( SELECt ull.risk_unit_id, MIN(ull.postRiskLevel) AS unitRiskLevel FROM ( SELECt ht1.* FROM ( SELECt a.*, rup.risk_unit_id FROM drh_risk_unit_post rup LEFT JOIN ( SELECt MIN(hft.risk_level) AS postRiskLevel, pr.post_id FROM ( SELECt hf.fk_id, MIN(hf.risk_level) AS risk_level FROM drh_post_result_hazar_factors hf GROUP BY hf.fk_id ) hft LEFT JOIN drh_post_result pr ON pr.id = hft.fk_id WHERe pr.post_id IS NOT NULL GROUP BY pr.post_id ) a ON a.post_id = rup.post_id LEFT JOIN drh_risk_unit ru ON ru.id = rup.risk_unit_id WHERe ru.unit_source = '1' ) ht1 UNIOn ALL SELECt ht2.* FROM ( SELECt a.*, rup.risk_unit_id FROM drh_risk_unit_post rup LEFT JOIN ( SELECt MIN(hft.risk_level) AS postRiskLevel, sm.post_id FROM ( SELECt hf.fk_id, MIN(hf.risk_level) AS risk_level FROM drh_post_result_hazar_factors hf GROUP BY hf.fk_id ) hft LEFT JOIN drh_safety_matters sm ON sm.id = hft.fk_id WHERe sm.post_id IS NOT NULL GROUP BY sm.post_id ) a ON a.post_id = rup.post_id LEFT JOIN drh_risk_unit ru ON ru.id = rup.risk_unit_id WHERe ru.unit_source = '2' ) ht2 ) ull GROUP BY ull.risk_unit_id ) tll LEFT JOIN sys_dict_item dt ON tll.unitRiskLevel = dt.item_value LEFT JOIN sys_dict d ON dt.dict_id = d.id WHERe d.dict_code = 'drh_inherent_risk_level' ) c ON c.risk_unit_id = rup.risk_unit_id ) g WHERe g.postRiskLevelText IS NOT NULL AND g.entid = 1 AND g.baseid = 1 ORDER BY g.create_time DESC LIMIT 10;
耗时22秒 接下来我们分析下
我们通过分析得出 这里面的tablederived2 的rows是一个笛卡尔积 他的数量等于id=2的所有操作 ,其实通过sql可以看出这里不难得出子查套子查询 导致查询效率低
一个主表 left 两个子查询后 外面又套了一个子查询
意思是 子查询 套子查询 导致查询结果比较慢,那么我们就这样优化 如下
SELECt DISTINCT ru.id AS unitId, ru.unit_name AS unitName, ru.create_time, ru.baseid, ru.entid
, p.id AS postId, p.post_name AS postName, IFNULL(a.patrolNum, 0) AS patrolNum
, IFNULL(ht.hiddenNum, 0) AS hiddenNum, b.postRiskLevel
, b.postRiskLevelText, c.unitRiskLevel, c.unitRiskLevelText
FROM drh_risk_unit_post rup
LEFT JOIN drh_risk_unit ru ON ru.id = rup.risk_unit_id
LEFT JOIN ent_post p ON p.id = rup.post_id
LEFT JOIN (
SELECt COUNT(1) AS patrolNum, pp.post_id
FROM drh_post_patrol pp
GROUP BY pp.post_id
) a
ON a.post_id = rup.post_id
LEFT JOIN (
SELECt COUNT(1) AS hiddenNum, h.post_id
FROM drh_hidden h
GROUP BY h.post_id
) ht
ON ht.post_id = rup.post_id
LEFT JOIN
(
SELECt llt.*, dt.item_text AS postRiskLevelText
FROM (
SELECt ht1.*
FROM (
SELECt a.*, rup.risk_unit_id
FROM drh_risk_unit_post rup
LEFT JOIN (
SELECt MIN(hft.risk_level) AS postRiskLevel, pr.post_id
FROM (
SELECt hf.fk_id, MIN(hf.risk_level) AS risk_level
FROM drh_post_result_hazar_factors hf
GROUP BY hf.fk_id
) hft
LEFT JOIN drh_post_result pr ON pr.id = hft.fk_id
WHERe pr.post_id IS NOT NULL
GROUP BY pr.post_id
) a
ON a.post_id = rup.post_id
LEFT JOIN drh_risk_unit ru ON ru.id = rup.risk_unit_id
WHERe ru.unit_source = '1'
) ht1
UNIOn ALL
SELECt ht2.*
FROM (
SELECt a.*, rup.risk_unit_id
FROM drh_risk_unit_post rup
LEFT JOIN (
SELECt MIN(hft.risk_level) AS postRiskLevel, sm.post_id
FROM (
SELECt hf.fk_id, MIN(hf.risk_level) AS risk_level
FROM drh_post_result_hazar_factors hf
GROUP BY hf.fk_id
) hft
LEFT JOIN drh_safety_matters sm ON sm.id = hft.fk_id
WHERe sm.post_id IS NOT NULL
GROUP BY sm.post_id
) a
ON a.post_id = rup.post_id
LEFT JOIN drh_risk_unit ru ON ru.id = rup.risk_unit_id
WHERe ru.unit_source = '2'
) ht2
) llt
LEFT JOIN sys_dict_item dt ON llt.postRiskLevel = dt.item_value
LEFT JOIN sys_dict d ON dt.dict_id = d.id
WHERe d.dict_code = 'drh_inherent_risk_level'
)
b
ON b.risk_unit_id = rup.risk_unit_id
AND b.post_id = rup.post_id
LEFT JOIN (
SELECt tll.*, dt.item_text AS unitRiskLevelText
FROM (
SELECt ull.risk_unit_id, MIN(ull.postRiskLevel) AS unitRiskLevel
FROM (
SELECt ht1.*
FROM (
SELECt a.*, rup.risk_unit_id
FROM drh_risk_unit_post rup
LEFT JOIN (
SELECt MIN(hft.risk_level) AS postRiskLevel, pr.post_id
FROM (
SELECt hf.fk_id, MIN(hf.risk_level) AS risk_level
FROM drh_post_result_hazar_factors hf
GROUP BY hf.fk_id
) hft
LEFT JOIN drh_post_result pr ON pr.id = hft.fk_id
WHERe pr.post_id IS NOT NULL
GROUP BY pr.post_id
) a
ON a.post_id = rup.post_id
LEFT JOIN drh_risk_unit ru ON ru.id = rup.risk_unit_id
WHERe ru.unit_source = '1'
) ht1
UNIOn ALL
SELECt ht2.*
FROM (
SELECt a.*, rup.risk_unit_id
FROM drh_risk_unit_post rup
LEFT JOIN (
SELECt MIN(hft.risk_level) AS postRiskLevel, sm.post_id
FROM (
SELECt hf.fk_id, MIN(hf.risk_level) AS risk_level
FROM drh_post_result_hazar_factors hf
GROUP BY hf.fk_id
) hft
LEFT JOIN drh_safety_matters sm ON sm.id = hft.fk_id
WHERe sm.post_id IS NOT NULL
GROUP BY sm.post_id
) a
ON a.post_id = rup.post_id
LEFT JOIN drh_risk_unit ru ON ru.id = rup.risk_unit_id
WHERe ru.unit_source = '2'
) ht2
) ull
GROUP BY ull.risk_unit_id
) tll
LEFT JOIN sys_dict_item dt ON tll.unitRiskLevel = dt.item_value
LEFT JOIN sys_dict d ON dt.dict_id = d.id
WHERe d.dict_code = 'drh_inherent_risk_level'
)
c
ON c.risk_unit_id = rup.risk_unit_id
WHERe
b.postRiskLevelText IS NOT NULL
and ru.entid = 1
and ru.baseid = 1
ORDER BY ru.create_time DESC
LIMIT 10
我们这里验证一下是否是这样
通过验证我们发现1.多秒就执行完了 原先需要20秒
早cpu高峰的时候
1 通过top命令找到那台机器连接我们的mysql比较耗CPU
2 通过 top -H -p PID 找到我们mysql那个物理进程比较耗费cpu
然后根据sql找到当时执行的sql或者是
找到我们的后台程序对应的数据库监控工具进行查询哪些比较慢
我的web后台使用到了druid 通过druid监控也可以查询到一些慢查询的sql
参考:https://www.isolves.com/it/sjk/MYSQL/2022-03-11/51075.html
http://www.muzhuangnet.com/show/44458.html
http://t.zoukankan.com/wyy123-p-9258513.html
https://blog.csdn.net/asd051377305/article/details/113979657



