自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

慢SQL探秘之為什么我的SQL很慢卻沒記錄在慢查詢?nèi)罩纠?/h1>

數(shù)據(jù)庫 MySQL
本文將總結(jié)一些比較常見的運行比較慢但不會被記錄在慢SQL日志里的情況。另外,慢SQL的計算方式在MySQL8.0新版本中有變化,因此,將通過對比MySQL5.7(MySQL5.7.38)與MySQL8.0(MySQL8.0.33)進行總結(jié)。

在MySQL數(shù)據(jù)庫中,想了解數(shù)據(jù)庫運行情況的重要指標(biāo)之一是慢SQL。而并非如某些人所說的所有運行慢的SQL都會被記錄在慢SQL日志(或日志表)里,抑或是沒有慢SQL就代表沒有運行慢的SQL。本文將總結(jié)一些比較常見的運行比較慢但不會被記錄在慢SQL日志里的情況。另外,慢SQL的計算方式在MySQL8.0新版本中有變化,因此,將通過對比MySQL5.7(MySQL5.7.38)與MySQL8.0(MySQL8.0.33)進行總結(jié)。

1.  準(zhǔn)備工作

部署了兩套環(huán)境,分別是MySQL5.7(MySQL5.7.38)版本及MySQL8.0(MySQL8.0.33)版本。另外為了后續(xù)進行慢SQL測試,此時先創(chuàng)建一張測試表并清空慢SQL日志表。

(1)創(chuàng)建測試表及數(shù)據(jù)

創(chuàng)建測試表及測試數(shù)據(jù),便于后續(xù)測試。本次通過創(chuàng)建一張1000W記錄的表進行測試。

然后再添加個字段。

mysql> call sp_createNum(10000000);
Query OK, 1611392 rows affected (38.70 sec)
mysql> select  count(*) from  testdb.nums;
+----------+
| count(*) |
+----------+
| 10000000 |
+----------+
1 row in set (3.70 sec)
mysql> alter table testdb.nums add c1 varchar(20);
Query OK, 0 rows affected (17.83 sec)
Records: 0  Duplicates: 0  Warnings: 0

(2)清空慢SQL日志表

測試前先清空慢SQL日志表mysql.slow_log,清空方法如下:

mysql> select  count(*) from mysql.slow_log;
+----------+
| count(*) |
+----------+
|        2 |
+----------+
1 row in set (0.00 sec)
# 需先關(guān)閉慢SQL監(jiān)控開關(guān)
mysql> set global slow_query_log=0;
Query OK, 0 rows affected (0.00 sec)
# truncate 方式清空慢SQL日志表
mysql> truncate table  mysql.slow_log;
Query OK, 0 rows affected (0.00 sec)
mysql> select  count(*) from mysql.slow_log;
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)
# 清理完畢后開啟慢SQL監(jiān)控
mysql> set global slow_query_log=1;
Query OK, 0 rows affected (0.00 sec)

2.  未開啟慢SQL監(jiān)控

查看MySQL是否開啟MySQL的方法如下:

mysql> SHOW GLOBAL VARIABLES LIKE 'slow_query_log';
+----------------+-------+
| Variable_name  | Value |
+----------------+-------+
| slow_query_log | ON    |
+----------------+-------+
1 row in set (0.00 sec)

其中value值為ON (或1),則代表開啟了慢SQL監(jiān)控。MySQL各個版本查看的方法均一樣。

另外和慢SQL相關(guān)的其他主要參數(shù)如下:

  • slow_query_log: 這個參數(shù)用于啟用或禁用慢SQL監(jiān)控。設(shè)置為1表示啟用,0表示禁用。默認值為0(禁用)。
  • log_output:日志存儲方式(不僅僅是慢SQL日志),默認值為'FILE'。當(dāng)log_output='FILE'表示將日志存入文件;當(dāng)log_output='TABLE'表示將日志存入數(shù)據(jù)庫中的mysql.slow_log表里;當(dāng)log_output='FILE,TABLE'表示既存儲到日志文件又存儲到mysql.slow_log表里。
  • slow_query_log_file: 慢SQL日志文件的路徑和文件名(5.5等低版本參數(shù)為log_slow_queries)??梢圆辉O(shè)置該參數(shù),系統(tǒng)則會默認給一個缺省的文件host_name-slow.log。
  • long_query_time: 用于定義慢SQL的閾值時間,單位為秒。執(zhí)行時間超過該閾值的SQL語句將被記錄到慢SQL日志中。默認值為10秒。
  • log_queries_not_using_indexes:如果設(shè)置為1,則將未使用索引的查詢也記錄到慢查詢?nèi)罩局?。默認值為0(禁用)。
  • log_slow_admin_statements: 如果設(shè)置為1,則會記錄部分管理命令(例如ALTER TABLE)到慢SQL日志中。默認值為0(禁用),本文后續(xù)也會繼續(xù)演示介紹。
  • log_slow_extra: 如果設(shè)置為1,則除了慢SQL日志的標(biāo)準(zhǔn)輸出之外,還將在日志中包括額外的信息,如用戶、主機、客戶端命令等。默認值為0(禁用)。
  • log_slow_slave_statements: 如果設(shè)置為1,則將從服務(wù)器執(zhí)行的慢SQL記錄到主服務(wù)器的慢SQL日志中。默認值為0(禁用)。
  • min_examined_row_limit: 僅在查詢的行數(shù)超過指定值時,才記錄到慢SQL日志中。默認值為0,表示不限制。

3.  SQL運行時間小于慢SQL監(jiān)控閾值時間

第一部分已經(jīng)介紹了和慢SQL相關(guān)的參數(shù)中的long_query_time,即慢SQL閾值。所以,當(dāng)SQL運行時間小于該閾值時,對于的SQL將不會記錄在慢SQL日志中。查看和修改慢SQL監(jiān)控閾值的方法如下:

# 查看慢SQL閾值
mysql> SHOW GLOBAL VARIABLES LIKE 'long_query_time';
+-----------------+----------+
| Variable_name   | Value    |
+-----------------+----------+
| long_query_time | 0.500000 |
+-----------------+----------+
1 row in set (0.00 sec)
# 設(shè)置慢SQL閾值
mysql> set global long_query_time=0.6;
Query OK, 0 rows affected (0.00 sec)
# 設(shè)置完成后可以查看全局的閾值
mysql> SHOW GLOBAL VARIABLES LIKE 'long_query_time';
+-----------------+----------+
| Variable_name   | Value    |
+-----------------+----------+
| long_query_time | 0.600000 |
+-----------------+----------+
1 row in set (0.01 sec)
# 但是當(dāng)前會話的慢SQL閾值是沒變的,這個同其他包含全局和會話級的參數(shù)類似
mysql> SHOW  VARIABLES LIKE 'long_query_time';
+-----------------+----------+
| Variable_name   | Value    |
+-----------------+----------+
| long_query_time | 0.500000 |
+-----------------+----------+
1 row in set (0.00 sec)

注:對于不同的數(shù)據(jù)庫需按照實際情況設(shè)置慢SQL監(jiān)控的閾值,例如TP業(yè)務(wù)的實例且配置相對較好時,建議閾值設(shè)置的較低;如果是AP類型業(yè)務(wù),則適當(dāng)放寬慢SQL的閾值。

4. 鎖等待或事務(wù)等待的SQL

開啟2個事務(wù),然后模擬鎖等待情況。

(1)MySQL5.7 中測試

首先測試MySQL5.7版本的情況:

事務(wù)1

事務(wù)2

mysql> begin;

Query OK, 0 rows affected (0.00 sec)


mysql> select now();

+---------------------+

| now()               |

+---------------------+

| 2024-03-24 20:40:47 |

+---------------------+

1 row in set (0.00 sec)


mysql> update testdb.nums set c1=id where id<=5;

Query OK, 5 rows affected (7.85 sec)

Rows matched: 5  Changed: 5  Warnings: 0


mysql> select now();

+---------------------+

| now()               |

+---------------------+

| 2024-03-24 20:41:07 |

+---------------------+

1 row in set (0.00 sec)



mysql> begin;

Query OK, 0 rows affected (0.00 sec)


mysql> select now();

+---------------------+

| now()               |

+---------------------+

| 2024-03-24 20:41:20 |

+---------------------+

1 row in set (0.00 sec)


mysql> update testdb.nums set c1=id where id<3;

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> select now();

+---------------------+

| now()               |

+---------------------+

| 2024-03-24 20:42:55 |

+---------------------+

1 row in set (0.00 sec)

mysql> select  * from mysql.slow_log\G

*************************** 1. row ***************************

    start_time: 2024-03-24 20:41:03.204598

     user_host: root[root] @ localhost []

    query_time: 00:00:07.853949

     lock_time: 00:00:00.000089

     rows_sent: 0

 rows_examined: 10000000

            db: testdb

last_insert_id: 0

     insert_id: 0

     server_id: 1

      sql_text: update testdb.nums set c1=id where id<=5

     thread_id: 2

1 row in set (0.00 sec)

mysql> select  * from mysql.slow_log\G

*************************** 1. row ***************************

    start_time: 2024-03-24 20:41:03.204598

     user_host: root[root] @ localhost []

    query_time: 00:00:07.853949

     lock_time: 00:00:00.000089

     rows_sent: 0

 rows_examined: 10000000

            db: testdb

last_insert_id: 0

     insert_id: 0

     server_id: 1

      sql_text: update testdb.nums set c1=id where id<=5

     thread_id: 2

1 row in set (0.00 sec)

從測試情況來看,MySQL5.7的鎖等待超時的SQL是沒有被記錄在慢SQL日志中的

(2)MySQL8.0中測試

事務(wù)1

事務(wù)2

mysql> begin;

Query OK, 0 rows affected (0.00 sec)


mysql> select now();

+---------------------+

| now()               |

+---------------------+

| 2024-03-24 20:59:20 |

+---------------------+

1 row in set (0.00 sec)


mysql> update testdb.nums set c1=id where id<=5;

Query OK, 5 rows affected (12.67 sec)

Rows matched: 5  Changed: 5  Warnings: 0



mysql> select now();

+---------------------+

| now()               |

+---------------------+

| 2024-03-24 21:00:01 |

+---------------------+

1 row in set (0.00 sec)



mysql> select  *,CONVERT(sql_text USING utf8mb4)sql_text2  from mysql.slow_log\G

*************************** 1. row ***************************

    start_time: 2024-03-24 20:59:55.819649

     user_host: root[root] @ localhost []

    query_time: 00:00:12.676771

     lock_time: 00:00:00.000003

     rows_sent: 0

 rows_examined: 10000000

            db: testdb

last_insert_id: 0

     insert_id: 0

     server_id: 1

      sql_text: 0x757064617465207465737464622E6E756D73207365742063313D69642077686572652069643C3D35

     thread_id: 87

     sql_text2: update testdb.nums set c1=id where id<=5



mysql> begin;

Query OK, 0 rows affected (0.00 sec)


mysql> select now();

+---------------------+

| now()               |

+---------------------+

| 2024-03-24 21:02:21 |

+---------------------+

1 row in set (0.00 sec)


mysql> update testdb.nums set c1=id where id<3;

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction


mysql> select now();

+---------------------+

| now()               |

+---------------------+

| 2024-03-24 21:03:41 |

+---------------------+

1 row in set (0.00 sec)


mysql>  select  *,CONVERT(sql_text USING utf8mb4)sql_text2  from mysql.slow_log\G

*************************** 1. row ***************************

    start_time: 2024-03-24 20:59:55.819649

     user_host: root[root] @ localhost []

    query_time: 00:00:12.676771

     lock_time: 00:00:00.000003

     rows_sent: 0

 rows_examined: 10000000

            db: testdb

last_insert_id: 0

     insert_id: 0

     server_id: 1

      sql_text: 0x757064617465207465737464622E6E756D73207365742063313D69642077686572652069643C3D35

     thread_id: 87

     sql_text2: update testdb.nums set c1=id where id<=5

*************************** 2. row ***************************

    start_time: 2024-03-24 21:03:31.882874

     user_host: root[root] @ localhost []

    query_time: 00:01:00.006259

     lock_time: 00:01:00.005760

     rows_sent: 0

 rows_examined: 1

            db: testdb

last_insert_id: 0

     insert_id: 0

     server_id: 1

      sql_text: 0x757064617465207465737464622E6E756D73207365742063313D69642077686572652069643C33

     thread_id: 88

     sql_text2: update testdb.nums set c1=id where id<3

2 rows in set (0.00 sec)

MySQL8.0中,鎖等待超時的SQL也會被記錄在慢SQL記錄中了,這與MySQL8.0后續(xù)新版中慢SQL的計算方式有調(diào)整有關(guān)系。

圖片

5. 管理類SQL

管理類SQL指的是alter table、alter user等,默認情況下,此類操作雖然比較慢,超過了慢SQL日志監(jiān)控的閾值,但是也不會記錄在慢SQL日志中。不過可以調(diào)整參數(shù)log_slow_admin_statements來控制是否記錄此類SQL。

(1)默認情況

mysql> use testdb;
Database changed
mysql> alter table testdb.nums add primary key (id);
Query OK, 0 rows affected (1 min 10.93 sec)
Records: 0  Duplicates: 0  Warnings: 0


mysql> select * from mysql.slow_log
    -> \G
Empty set (0.00 sec)

此時,雖然加主鍵的SQL運行了1分鐘以上,但是慢SQL日志表里無此記錄。

圖片

MySQL8.0 中同樣如此。

圖片


(2)調(diào)整log_slow_admin_statements

log_slow_admin_statements參數(shù)是控制記錄超時的管理操作SQL是否記錄到慢查詢?nèi)罩尽DJ情況下的值是0,也就是不記錄;而將值改為1時,此類SQL將會被記錄。

mysql> set global  log_slow_admin_statements=1;
Query OK, 0 rows affected (0.00 sec)


mysql> alter table testdb.nums add key idx_c1(c1);
Query OK, 0 rows affected (16.54 sec)
Records: 0  Duplicates: 0  Warnings: 0


mysql> select * from mysql.slow_log\G
*************************** 1. row ***************************
    start_time: 2024-03-24 21:39:43.181950
     user_host: root[root] @ localhost []
    query_time: 00:00:16.545439
     lock_time: 00:00:00.001927
     rows_sent: 0
 rows_examined: 0
            db: testdb
last_insert_id: 0
     insert_id: 0
     server_id: 1
      sql_text: alter table testdb.nums add key idx_c1(c1)
     thread_id: 8
1 row in set (0.00 sec)


mysql> select version();
+---------------+
| version()     |
+---------------+
| 5.7.38-41-log |
+---------------+
1 row in set (0.00 sec)

此時,添加索引的操作將被記錄。

圖片

MySQL8.0中同樣適用。

圖片


6.  掃描記錄少于閾值的SQL

MySQL中掃描記錄少于閾值由min_examined_row_limit參數(shù)控制,默認值為0,即如果SQL掃描的行數(shù)少于此值時,將不會被記錄在慢SQL日志中,否則將會被記錄。由于默認值是0,因此掃描行數(shù)>=0的且符合其他記錄慢SQL的條件時便會被記錄。如果想忽略掃描數(shù)據(jù)量較少,但是又不想記錄超過閾值的SQL,則可以調(diào)整min_examined_row_limit來解決。

(1)默認情況

測試一下默認情況.

mysql> show global variables like 'min_examined_row_limit';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| min_examined_row_limit | 0     |
+------------------------+-------+
1 row in set (0.00 sec)
#c1<=999,可以隱式轉(zhuǎn)換導(dǎo)致無法走索引,使其變慢,便于測試
mysql> select count(*) from testdb.nums where c1<=999;
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (1.70 sec)
mysql> select * from mysql.slow_log\G
*************************** 1. row ***************************
    start_time: 2024-03-24 21:48:46.005622
     user_host: root[root] @ localhost []
    query_time: 00:00:01.691788
     lock_time: 00:00:00.000092
     rows_sent: 1
 rows_examined: 10000000
            db: testdb
last_insert_id: 0
     insert_id: 0
     server_id: 25455
      sql_text: select count(*) from testdb.nums where c1<=999
     thread_id: 8

圖片

此時慢SQL會被記錄。MySQL8.0中同樣如此。

圖片

(2)修改參數(shù)

為了測試,此時將min_examined_row_limit值設(shè)置為20000000,然后測試是否還會被記錄。

mysql> set min_examined_row_limit=20000000;
Query OK, 0 rows affected (0.00 sec)
mysql> select count(*) from testdb.nums where c1<=999;
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (1.70 sec)
mysql> select * from mysql.slow_log\G
*************************** 1. row ***************************
    start_time: 2024-03-24 21:48:46.005622
     user_host: root[root] @ localhost []
    query_time: 00:00:01.691788
     lock_time: 00:00:00.000092
     rows_sent: 1
 rows_examined: 10000000
            db: testdb
last_insert_id: 0
     insert_id: 0
     server_id: 25455
      sql_text: select count(*) from testdb.nums where c1<=999
     thread_id: 8
1 row in set (0.00 sec)

圖片

可見,此時的慢SQL還是之前的,即修改后,即使SQL運行時間超過了慢SQL閾值,但是掃描行數(shù)低于min_examined_row_limit參數(shù)指定的值,此時也不會被記錄。MySQL同樣如此。

圖片

7. 其他SQL

除了以上的情況外,復(fù)制線程的查詢、被DBAkill的正在運行的SQL或部分未運行完畢的SQL也不會記錄在慢SQL日志中(不過部分情況再MySQL8.0中有所變更),因此需要大家根據(jù)實際情況多總結(jié)及測試。

責(zé)任編輯:姜華 來源: 數(shù)據(jù)庫干貨鋪
相關(guān)推薦

2020-12-22 09:10:05

SQLMysql 數(shù)據(jù)庫

2020-08-10 11:20:59

索引MySQL數(shù)據(jù)庫

2020-08-14 09:11:29

RedisQPS數(shù)據(jù)庫

2024-11-28 09:51:35

SQL日志Go項目

2020-01-22 16:36:52

MYSQL開源數(shù)據(jù)庫

2023-09-01 07:31:24

2011-04-02 16:39:53

SQL Server查詢

2011-04-02 16:45:58

SQL Server查詢優(yōu)化

2023-11-30 15:37:37

MySQL數(shù)據(jù)庫

2011-06-28 08:32:40

MySQL慢查詢?nèi)罩?/a>

2021-08-03 17:15:19

SQL 慢 SQL

2017-04-01 19:00:25

MySQL慢查詢

2020-03-05 16:55:56

索引數(shù)據(jù)庫SQL

2020-10-29 09:19:11

索引查詢存儲

2021-07-30 07:28:16

SQL優(yōu)化日志

2010-07-09 09:08:43

2025-03-27 03:22:00

2017-05-23 16:26:26

MySQL優(yōu)化處理

2018-08-16 08:03:21

Python語言解釋器

2010-11-25 11:07:28

MySQL慢查詢
點贊
收藏

51CTO技術(shù)棧公眾號