SQL優化工具


十四、SQL優化工具

1 慢查詢日志

MySQL的慢查詢日志是MySQL提供的一種日志記錄,它用來記錄在MySQL中響應時間超過閥值的語句,具體指運行時間超過long_query_time值的SQL,則會被記錄到慢查詢日志中。long_query_time的默認值為10,運行10秒以上的SQL語句會被記錄下來。由慢查詢日志來查看哪些SQL超出了我們的最大忍耐時間值,比如一條sql執行超過5秒鍾,我們就算慢SQL,希望能收集超過5秒的sql,結合explain進行全面分析。

1.1 開啟慢查詢日志

默認情況下,MySQL數據庫沒有開啟慢查詢日志,需要我們手動來設置這個參數。如果不是調優需要,一般不建議開啟該參數,因為開啟慢查詢日志或多或少會帶來一定的性能影響。

首先查看mysql的慢查詢日志是否開啟,通過如下命令:

SHOW VARIABLES LIKE '%slow_query_log%';

image

slow_query_logOFF表示關閉了慢查詢日志,slow_query_log_file表示日志的存放位置。

使用如下命令開啟慢查詢日志:

SET GLOBAL slow_query_log = 1;

使用此方法開啟了慢查詢日志只對當前數據庫生效,如果MySQL重啟后則會失效。如果要永久生效,就必須修改配置文件my.cnf。修改如下位置即可:

[mysqld]
slow_query_log =1
slow_query_log_file=/var/lib/mysql/Heygo-slow.log

1.2 修改參數

開啟慢查詢日志后,什么樣的SQL會記錄到慢查詢里面?這個是由參數long_query_time控制,默認情況下long_query_time的值為10秒,使用如下命令查看慢SQL記錄的閾值:

SHOW VARIABLES LIKE 'long_query_time%';

另外,運行時間正好等於long_query_time並不會被記錄下來。

可以手動修改這個閾值,通過命令臨時修改(永久修改需要修改my.cnf):

SET GLOBAL long_query_time = 5;

執行之后需要重新連接或者新開一個客戶端連接才能看到修改值。

1.3 查看日志

現在,執行如下語句,一定會被慢日志記錄:

SELECT sleep(6); 

慢查詢日志文件默認在/var/lib/mysql/ 下,后綴為-slow.log,查看一下:

cat 68926f356828-slow.log 

mysqld, Version: 5.7.37 (MySQL Community Server (GPL)). started with:
Tcp port: 3306  Unix socket: /var/run/mysqld/mysqld.sock
Time                 Id Command    Argument
# Time: 2022-01-28T10:57:27.035023Z
# User@Host: root[root] @  [192.168.142.3]  Id:     7
# Query_time: 6.000578  Lock_time: 0.000000 Rows_sent: 1  Rows_examined: 0
SET timestamp=1643367447;
SELECT sleep(6);

查詢當前系統中有多少條慢查詢記錄:

SHOW GLOBAL STATUS LIKE '%Slow_queries%';

1.4 日志分析命令

在生產環境中,如果要手工分析日志,查找、分析SQL,顯然是個體力活,MySQL提供了日志分析工具mysqldumpslow

# 查看幫助:mysqldumpslow --help
Usage: mysqldumpslow [ OPTS... ] [ LOGS... ]

Parse and summarize the MySQL slow query log. Options are

  --verbose    verbose
  --debug      debug
  --help       write this text to standard output

  -v           verbose
  -d           debug
  -s ORDER     what to sort by (al, at, ar, c, l, r, t), 'at' is default # 表示按何種方式排序 默認為at
                al: average lock time  # 按平均鎖定時間
                ar: average rows sent  # 按平均返回記錄數
                at: average query time  # 按平均查詢時間
                 c: count  # 按訪問次數
                 l: lock time  # 按鎖定時間
                 r: rows sent  # 按返回記錄
                 t: query time   # 按查詢時間
  -r           reverse the sort order (largest last instead of first)
  -t NUM       just show the top n queries  # 只顯示前N條查詢
  -a           don't abstract all numbers to N and strings to 'S'
  -n NUM       abstract numbers with at least n digits within names
  -g PATTERN   grep: only consider stmts that include this string  # 匹配指定字符串
  -h HOSTNAME  hostname of db server for *-slow.log filename (can be wildcard),
               default is '*', i.e. match all
  -i NAME      name of server instance (if using mysql.server startup script)
  -l           don't subtract lock time from total time

常見使用示例:

# 得到返回記錄集最多的10個SQL
mysqldumpslow -s r -t 10 /var/lib/mysql/68926f356828-slow.log 
# 得到訪問次數最多的10個SQL
mysqldumpslow -s c -t 10 /var/lib/mysql/68926f356828-slow.log
# 得到按照時間排序的前10條里面含有左連接的查詢語句
mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/68926f356828-slow.log
# 在使用這些命令時結合 | 和more使用,因為如果日志很大,可能會刷屏
mysqldumpslow -s r -t 10 /var/lib/mysql/68926f356828-slow.log | more

2 Show Profile

Show Profile是mysql提供可以用來分析當前會話中語句執行的資源消耗情況,可以用於SQL的調優測量。默認情況下,參數處於關閉狀態,並保存最近15次的運行結果。

2.1 開啟Show Profile

查看Show Profile是否開啟,使用如下命令:

SHOW VARIABLES LIKE 'profiling%';

開啟Show Profile:

SET profiling = ON;

2.2 使用Show Profile

下面運行幾條SQL嘗試一下:

# 普通sql
select * from tbl_emp;
select * from tbl_emp e inner join tbl_dept d on e.deptId = d.id;
select * from tbl_emp e left join tbl_dept d on e.deptId = d.id;

# 慢sql
select * from emp group by id%10 limit 150000;
select * from emp group by id%10 limit 150000;
select * from emp group by id%20 order by 5;

查看結果:

mysql> SHOW PROFILES;
+----------+------------+----------------------------------------------------------------------+
| Query_ID | Duration   | Query                                                                |
+----------+------------+----------------------------------------------------------------------+
|        1 | 0.00052700 | show variables like 'profiling%'                                     |
|        2 | 0.00030300 | select * from tbl_emp                                                |
|        3 | 0.00010650 | select * from tbl_emp e inner join tbl_dept d on e.'deptId' = d.'id' |
|        4 | 0.00031625 | select * from tbl_emp e inner join tbl_dept d on e.deptId = d.id     |
|        5 | 0.00042100 | select * from tbl_emp e left join tbl_dept d on e.deptId = d.id      |
|        6 | 0.38621875 | select * from emp group by id%20 limit 150000                        |
|        7 | 0.00014900 | select * from emp group by id%20 order by 150000                     |
|        8 | 0.38649000 | select * from emp group by id%20 order by 5                          |
|        9 | 0.06782700 | select COUNT(*) from emp                                             |
|       10 | 0.35434400 | select * from emp group by id%10 limit 150000                        |
+----------+------------+----------------------------------------------------------------------+

2.3 診斷SQL

查看SQL語句執行的具體流程以及每個步驟花費的時間:

SHOW PROFILE cpu,block io FOR QUERY SQL編號;
# 查詢參數解釋:

# ALL:顯示所有的開銷信息
# BLOCK IO:顯示塊IO相關開銷
# CONTEXT SWITCHES:上下文切換相關開銷
# CPU:顯示CPU相關開銷信息
# IPC:顯示發送和接收相關開銷信息
# MEMORY:顯示內存相關開銷信息
# PAGE FAULTS:顯示頁面錯誤相關開銷信息
# SOURCE:顯示和Source_function,Source_file,Source_line相關的開銷信息
# SWAPS:顯示交換次數相關開銷的信息

示例:

mysql> SHOW PROFILE cpu,block io FOR QUERY 2;
+----------------------+----------+----------+------------+--------------+---------------+
| Status               | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+----------------------+----------+----------+------------+--------------+---------------+
| starting             | 0.000055 | 0.000000 |   0.000000 |            0 |             0 |
| checking permissions | 0.000007 | 0.000000 |   0.000000 |            0 |             0 |
| Opening tables       | 0.000011 | 0.000000 |   0.000000 |            0 |             0 |
| init                 | 0.000024 | 0.000000 |   0.000000 |            0 |             0 |
| System lock          | 0.000046 | 0.000000 |   0.000000 |            0 |             0 |
| optimizing           | 0.000018 | 0.000000 |   0.000000 |            0 |             0 |
| statistics           | 0.000008 | 0.000000 |   0.000000 |            0 |             0 |
| preparing            | 0.000019 | 0.000000 |   0.000000 |            0 |             0 |
| executing            | 0.000003 | 0.000000 |   0.000000 |            0 |             0 |
| Sending data         | 0.000089 | 0.000000 |   0.000000 |            0 |             0 |
| end                  | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |
| query end            | 0.000003 | 0.000000 |   0.000000 |            0 |             0 |
| closing tables       | 0.000005 | 0.000000 |   0.000000 |            0 |             0 |
| freeing items        | 0.000006 | 0.000000 |   0.000000 |            0 |             0 |
| cleaning up          | 0.000006 | 0.000000 |   0.000000 |            0 |             0 |
+----------------------+----------+----------+------------+--------------+---------------+

如果你使用Navicat軟件,也可以在剖析中查看到這些數據。
image

如果status狀態出現以下幾種,需要警惕:

  • converting HEAP to MyISAM:查詢結果太大,內存都不夠用了往磁盤上搬了。
  • Creating tmp table:創建臨時表,mysql 先將拷貝數據到臨時表,然后用完再將臨時表刪除
  • Copying to tmp table on disk:把內存中臨時表復制到磁盤
  • locked:鎖表

3 SQL優化思路

配合慢查詢日志和Show Profile,梳理一下SQL的優化思路。當整個sql server變慢之后,可以按照如下方法進行分析:

  • 開啟慢查詢,捕獲慢sql

  • 使用explain對慢查詢日志中的sql進行分析

  • 使用show profile查詢sql在mysql服務器里面的執行細節和生命周期情況

  • 對sql數據庫服務器的參數進行調優


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM