MySQL exists關聯子查詢SQL效能及其低下最佳化之等值子查詢轉換
2018年4月20日,移動某平臺江蘇某業務系統發起SQL調優請求,在本次MySQL除錯過程中遇到了exists關聯子查詢導致的sql
效能及其低下,並且相關的SQL語句執行速度及其不穩定忽快忽慢;透過重寫相關SQL的exists部分修改成等值子查詢,相關sql的
效能得到極大提高,並且執行速度比較穩定。本次SQL最佳化過程記錄如下:
1、環境資訊:
作業系統版本:CENTOS 7.2.1151
資料庫版本:5.7.17-log
2、檢視MySQL慢日誌相關資訊
mysql>show variables like '%slow_query_%';
-+-------------------------------------------+--------------------------------------------------------------------------------+
| Variable_name | Value |
-+-------------------------------------------+--------------------------------------------------------------------------------+
|slow_query_log | ON |
|slow_query_log_file |/data/mysql/db/elog/slow.log |
-+-------------------------------------------+--------------------------------------------------------------------------------+
2、使用pt工具分析MySQL的慢日誌
cd /data/mysql/db/elog
pt-query-digest slow.log --since '2018-04-13 00:00:00' --until '2018-04-19 00:00:00' >>slow_report_log
效能及其低下,並且相關的SQL語句執行速度及其不穩定忽快忽慢;透過重寫相關SQL的exists部分修改成等值子查詢,相關sql的
效能得到極大提高,並且執行速度比較穩定。本次SQL最佳化過程記錄如下:
1、環境資訊:
作業系統版本:CENTOS 7.2.1151
資料庫版本:5.7.17-log
2、檢視MySQL慢日誌相關資訊
mysql>show variables like '%slow_query_%';
-+-------------------------------------------+--------------------------------------------------------------------------------+
| Variable_name | Value |
-+-------------------------------------------+--------------------------------------------------------------------------------+
|slow_query_log | ON |
|slow_query_log_file |/data/mysql/db/elog/slow.log |
-+-------------------------------------------+--------------------------------------------------------------------------------+
2、使用pt工具分析MySQL的慢日誌
cd /data/mysql/db/elog
pt-query-digest slow.log --since '2018-04-13 00:00:00' --until '2018-04-19 00:00:00' >>slow_report_log
3、檢視慢日誌分析報告slow_report_log
![](https://i.iter01.com/images/c11d4c4b4c9d91138ec2cfcc02802d3d79b3692bf028bff70fb70bbb39569ebf.png)
透過慢日誌分析報告發現兩條執行緩慢的SQL語句Query_ID分別是0xEA33702BDD78E0BA、0x56B6B418ADAAB135,其中
0xEA33702BDD78E0BA的響應時間佔據了整個資料庫時間的97.1%,是重點最佳化物件。
4、明確需要最佳化的物件
--第一條需要最佳化的重點物件0xEA33702BDD78E0BA
![](https://i.iter01.com/images/0f0d9b5b380509463ed9986c44acaf42cf4889202ad72c7f74982fca4f12d741.png)
--SQL執行計劃
![](https://i.iter01.com/images/8ce81197f8b6e5f3cb2929c2ba73d6b4472b23d74fca9e43ea1f5c121e8bda03.jpg)
--SQL執行統計資訊概要![](https://i.iter01.com/images/1b0009070ab66db347c1034abcf03251f2d9500e42e7dab66b30abcd66813af3.png)
--第二條要最佳化的SQL物件
0x56B6B418ADAAB135
![](https://i.iter01.com/images/792a88794bc5c309d0de97cbc8e184bfa943d786bc0271a9b192832d721d8509.png)
--SQL執行計劃
![](https://i.iter01.com/images/06f0e87b82b87da834b94ae0745ed69a4fa8955a3caee2034ad32e530f0adacf.jpg)
--SQL執行統計資訊概要
![](https://i.iter01.com/images/358574cb80f34a2133bd9f5f7df29c865fca81c397fa881e4bb9a7e752c7c60f.png)
5、首先看第一條SQL語句,自己的最佳化思路,確定SQL語句中慢的具體位置
--對第一條SQL語句拆分,以union為界分兩部分
--0xEA33702BDD78E0BA第一部分:0xEA33702BDD78E0BA_part1
![](https://i.iter01.com/images/7fcd3444e97cd8186ad305de23fc56667ddfdcc19a98d20473070ad80753e81c.png)
0xEA33702BDD78E0BA_part1部分SQL語句查詢只有13條記錄,執行速度非常快0.00秒完成
![](https://i.iter01.com/images/f1b32d3892578b7ad423bfcc30404815fc3614e986684523be4de08d0b920e37.jpg)
--0xEA33702BDD78E0BA第二部分:0xEA33702BDD78E0BA_part2
![](https://i.iter01.com/images/d6cad21f45c8679fc88797f4f3aa8c5415b82ee4f1891114f4ba08d5986792f9.png)
0xEA33702BDD78E0BA_part2部分SQL(該部分查詢正常出結果是103條資料)語句執行超過10s,超時退出
![](https://i.iter01.com/images/717bcebc7a524788207edd24ae5e6965e05c60b37d283a57b93d77133c4e2a11.jpg)
6、接下來著重關注0xEA33702BDD78E0BA第二部分:0xEA33702BDD78E0BA_part2
![](https://i.iter01.com/images/d6cad21f45c8679fc88797f4f3aa8c5415b82ee4f1891114f4ba08d5986792f9.png)
觀察SQL語句發現有EXISTS關聯子查詢,我的理解是,原先sql被最佳化器改寫,主查詢執行多次,每次主查詢sql都不同,
都會發起物理讀盤掃表。於是考慮將其改為等值連線子查詢:
![](https://i.iter01.com/images/435683cb8ebafc9ad733bfedc5a13f9c04009299b75afd8896bfee6986267c9f.jpg)
--SQL改寫後(查詢結果集與修改前一致):兩個等值查詢表結果集在記憶體,接下來是最終結果集匹配和過濾,執行速度只有0.01秒
![](https://i.iter01.com/images/53b2abca69faf4889f60438b1cd107d3cb38fb5063b86fca421c54c13af233eb.jpg)
7、修改後的完整SQL如下
![](https://i.iter01.com/images/18cfcad2c42ab66b7a68b47ce7dbb74f80bfa48c9a3eb7b09c6c7db48a21e6a7.jpg)
--修改後的sql執行速度,有原先的超過10s超時中斷退出降低到0.00秒以下。
![](https://i.iter01.com/images/2cdcdac7872b737c53a087b5e21462c8a1f3da13a098f0baf7c0a8b8ff44b3ab.jpg)
--SQL改寫後的執行計劃
![](https://i.iter01.com/images/72ca8e35d02bf00023510a6884652e4e3f1e8ed5bf9c8bec10e32d34a188ef94.jpg)
8、第二條SQL語句採用第一條SQL語句最佳化方法,將exists關聯子查詢改寫為表關聯的等值子查詢
--改寫前的執行效率
![](https://i.iter01.com/images/5906042d4fa1d756de60b1eaba82689c42de8f39a8ee231c59a7b083769db059.jpg)
--改寫後的執行效率
![](https://i.iter01.com/images/2df4be3c395f2a3b34b5caeed3a812efdb869e9c6a27fbc1476dbb7133016151.jpg)
--改寫後的SQL執行計劃
![](https://i.iter01.com/images/ca5088d980bd0d9c0efca3b9e3a7134d59e510499c80994a8651edbe9e2d8cdd.jpg)
9、總結
透過觀察SQL改寫前後的執行計劃,可以發現改寫後的SQL 執行中間結果集均已快取到記憶體(Using join buffer(Block Nested Loop)),記憶體結果集匹配過濾降低了表的物理IO,從而提高了SQL的執行效能。
![](https://i.iter01.com/images/c11d4c4b4c9d91138ec2cfcc02802d3d79b3692bf028bff70fb70bbb39569ebf.png)
透過慢日誌分析報告發現兩條執行緩慢的SQL語句Query_ID分別是0xEA33702BDD78E0BA、0x56B6B418ADAAB135,其中
0xEA33702BDD78E0BA的響應時間佔據了整個資料庫時間的97.1%,是重點最佳化物件。
4、明確需要最佳化的物件
--第一條需要最佳化的重點物件0xEA33702BDD78E0BA
![](https://i.iter01.com/images/0f0d9b5b380509463ed9986c44acaf42cf4889202ad72c7f74982fca4f12d741.png)
--SQL執行計劃
![](https://i.iter01.com/images/8ce81197f8b6e5f3cb2929c2ba73d6b4472b23d74fca9e43ea1f5c121e8bda03.jpg)
--SQL執行統計資訊概要
![](https://i.iter01.com/images/1b0009070ab66db347c1034abcf03251f2d9500e42e7dab66b30abcd66813af3.png)
--第二條要最佳化的SQL物件
0x56B6B418ADAAB135
![](https://i.iter01.com/images/792a88794bc5c309d0de97cbc8e184bfa943d786bc0271a9b192832d721d8509.png)
--SQL執行計劃
![](https://i.iter01.com/images/06f0e87b82b87da834b94ae0745ed69a4fa8955a3caee2034ad32e530f0adacf.jpg)
--SQL執行統計資訊概要
![](https://i.iter01.com/images/358574cb80f34a2133bd9f5f7df29c865fca81c397fa881e4bb9a7e752c7c60f.png)
5、首先看第一條SQL語句,自己的最佳化思路,確定SQL語句中慢的具體位置
--對第一條SQL語句拆分,以union為界分兩部分
--0xEA33702BDD78E0BA第一部分:0xEA33702BDD78E0BA_part1
![](https://i.iter01.com/images/7fcd3444e97cd8186ad305de23fc56667ddfdcc19a98d20473070ad80753e81c.png)
0xEA33702BDD78E0BA_part1部分SQL語句查詢只有13條記錄,執行速度非常快0.00秒完成
![](https://i.iter01.com/images/f1b32d3892578b7ad423bfcc30404815fc3614e986684523be4de08d0b920e37.jpg)
--0xEA33702BDD78E0BA第二部分:0xEA33702BDD78E0BA_part2
![](https://i.iter01.com/images/d6cad21f45c8679fc88797f4f3aa8c5415b82ee4f1891114f4ba08d5986792f9.png)
0xEA33702BDD78E0BA_part2部分SQL(該部分查詢正常出結果是103條資料)語句執行超過10s,超時退出
![](https://i.iter01.com/images/717bcebc7a524788207edd24ae5e6965e05c60b37d283a57b93d77133c4e2a11.jpg)
6、接下來著重關注0xEA33702BDD78E0BA第二部分:0xEA33702BDD78E0BA_part2
![](https://i.iter01.com/images/d6cad21f45c8679fc88797f4f3aa8c5415b82ee4f1891114f4ba08d5986792f9.png)
觀察SQL語句發現有EXISTS關聯子查詢,我的理解是,原先sql被最佳化器改寫,主查詢執行多次,每次主查詢sql都不同,
都會發起物理讀盤掃表。於是考慮將其改為等值連線子查詢:
![](https://i.iter01.com/images/435683cb8ebafc9ad733bfedc5a13f9c04009299b75afd8896bfee6986267c9f.jpg)
--SQL改寫後(查詢結果集與修改前一致):兩個等值查詢表結果集在記憶體,接下來是最終結果集匹配和過濾,執行速度只有0.01秒
![](https://i.iter01.com/images/53b2abca69faf4889f60438b1cd107d3cb38fb5063b86fca421c54c13af233eb.jpg)
7、修改後的完整SQL如下
![](https://i.iter01.com/images/18cfcad2c42ab66b7a68b47ce7dbb74f80bfa48c9a3eb7b09c6c7db48a21e6a7.jpg)
--修改後的sql執行速度,有原先的超過10s超時中斷退出降低到0.00秒以下。
![](https://i.iter01.com/images/2cdcdac7872b737c53a087b5e21462c8a1f3da13a098f0baf7c0a8b8ff44b3ab.jpg)
--SQL改寫後的執行計劃
![](https://i.iter01.com/images/72ca8e35d02bf00023510a6884652e4e3f1e8ed5bf9c8bec10e32d34a188ef94.jpg)
8、第二條SQL語句採用第一條SQL語句最佳化方法,將exists關聯子查詢改寫為表關聯的等值子查詢
--改寫前的執行效率
![](https://i.iter01.com/images/5906042d4fa1d756de60b1eaba82689c42de8f39a8ee231c59a7b083769db059.jpg)
--改寫後的執行效率
![](https://i.iter01.com/images/2df4be3c395f2a3b34b5caeed3a812efdb869e9c6a27fbc1476dbb7133016151.jpg)
--改寫後的SQL執行計劃
![](https://i.iter01.com/images/ca5088d980bd0d9c0efca3b9e3a7134d59e510499c80994a8651edbe9e2d8cdd.jpg)
9、總結
透過觀察SQL改寫前後的執行計劃,可以發現改寫後的SQL 執行中間結果集均已快取到記憶體(Using join buffer(Block Nested Loop)),記憶體結果集匹配過濾降低了表的物理IO,從而提高了SQL的執行效能。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29357786/viewspace-2153133/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 區分關聯子查詢和非關聯子查詢
- MySQL之連線查詢和子查詢MySql
- MySQL 相關子查詢MySql
- exists與in子查詢優化優化
- SQL查詢的:子查詢和多表查詢SQL
- mysql求交集:UNION ALL合併查詢,inner join內連線查詢,IN/EXISTS子查詢MySql
- MYsql 子查詢MySql
- MySQL子查詢MySql
- 什麼是SQL 語句中相關子查詢與非相關子查詢SQL
- sql-server不相關子查詢SQLServer
- sql-server相關子查詢SQLServer
- 【SQL】Oracle查詢轉換之 OR用法SQLOracle
- mysql-分組查詢-子查詢-連線查詢-組合查詢MySql
- ORACLE_OCP之SQL_子查詢OracleSQL
- StoneDB 子查詢最佳化
- 【SQL】Oracle查詢轉換之物化檢視查詢重寫SQLOracle
- 【MySQL】檢視&子查詢MySql
- MySQL 優化五(關聯查詢子查詢以及 in 的效率問題)(高階篇)MySql優化
- elasticsearch之exists查詢Elasticsearch
- 複雜查詢—子查詢
- MySQL查詢效能最佳化MySql
- MYSQL學習筆記25: 多表查詢(子查詢)[標量子查詢,列子查詢]MySql筆記
- MYSQL學習筆記26: 多表查詢|子查詢MySql筆記
- MySQL資料庫基礎——多表查詢:子查詢MySql資料庫
- MySQL全面瓦解11:子查詢和組合查詢MySql
- 關於關聯查詢sql的一次最佳化過程及其他SQL
- SQL語言基礎(子查詢)SQL
- 【SQL】Oracle查詢轉換之謂詞推送SQLOracle
- 子串查詢
- Laravel 通過子查詢建立動態關聯Laravel
- 【SQL】Oracle查詢轉換之檢視合併SQLOracle
- MySQL 查詢效能分析之 ExplainMySqlAI
- mysql三表關聯查詢MySql
- mysql 三表關聯查詢MySql
- Mysql常用sql語句(20)- 子查詢重點知識MySql
- Javaweb-子查詢JavaWeb
- 巢狀子查詢巢狀
- GORM subquery 子查詢GoORM