哈哈哈哈哈操欧洲电影,久草网在线,亚洲久久熟女熟妇视频,麻豆精品色,久久福利在线视频,日韩中文字幕的,淫乱毛视频一区,亚洲成人一二三,中文人妻日韩精品电影

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

MySQL數(shù)據(jù)庫慢查詢的排查思路和最佳實踐

馬哥Linux運維 ? 來源:馬哥Linux運維 ? 2026-04-24 14:40 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

背景與問題

數(shù)據(jù)庫慢查詢是導致應用響應緩慢最常見的原因之一。當業(yè)務人員反饋“頁面加載慢”、“查詢超時”、“系統(tǒng)卡頓”時,很多運維人員的第一反應是讓開發(fā)人員“加個索引”。但加索引只是優(yōu)化查詢的眾多手段之一,盲目加索引不僅可能無效,還可能適得其反。

真正的慢查詢優(yōu)化需要系統(tǒng)的方法:首先確認慢查詢的事實,然后分析查詢的執(zhí)行計劃,理解數(shù)據(jù)庫的查詢優(yōu)化器決策,找出真正的瓶頸所在,最后選擇最合適的優(yōu)化手段。優(yōu)化手段包括但不限于:創(chuàng)建合適的索引、重寫 SQL 語句、調整數(shù)據(jù)庫配置、優(yōu)化表結構、分表分庫、引入緩存等。

本文以 MySQL 為例,詳細講解慢查詢的排查思路、分析方法、優(yōu)化手段和最佳實踐。這些方法論同樣適用于 PostgreSQL、Oracle 等主流數(shù)據(jù)庫,只是具體命令和語法有所不同。

1 慢查詢的發(fā)現(xiàn)與確認

1.1 開啟慢查詢日志

MySQL 的慢查詢日志是排查慢查詢的基礎工具。默認情況下,慢查詢日志是關閉的。需要通過配置啟用。

查看當前慢查詢配置:

-- 查看慢查詢相關變量
SHOWVARIABLESLIKE'slow_query%';
SHOWVARIABLESLIKE'long_query_time';
SHOWVARIABLESLIKE'log_output';

-- 查看是否啟用了慢查詢日志
SHOWVARIABLESLIKE'slow_query_log';

-- 查看慢查詢日志文件路徑
SHOWVARIABLESLIKE'slow_query_log_file';

配置慢查詢日志:

-- 開啟慢查詢日志
SETGLOBALslow_query_log ='ON';

-- 設置慢查詢閾值為 1 秒(可以是浮點數(shù))
SETGLOBALlong_query_time =1;

-- 設置日志輸出格式(TABLE 或 FILE)
SETGLOBALlog_output ='FILE';

-- 設置慢查詢日志文件路徑
SETGLOBALslow_query_log_file ='/var/log/mysql/slow.log';

上述配置重啟后會丟失,需要寫入配置文件永久生效。編輯 MySQL 配置文件(/etc/mysql/my.cnf或/etc/my.cnf):

[mysqld]
# 開啟慢查詢日志
slow_query_log = 1

# 慢查詢日志文件路徑
slow_query_log_file = /var/log/mysql/slow.log

# 慢查詢閾值(秒)
long_query_time = 1

# 記錄沒有使用索引的查詢
log_queries_not_using_indexes = 1

# 將慢查詢記錄到表(mysql.general_log)
log_output = FILE

重啟 MySQL 服務使配置生效:

systemctl restart mysql
systemctl restart mysqld

1.2 慢查詢日志格式解讀

MySQL 慢查詢日志記錄了每次慢查詢的詳細信息:

# Time: 2024-01-15T1045.123456Z
# User@Host: app_user[app_user] @ localhost []
# Query_time: 5.234567 Lock_time: 0.001234 Rows_sent: 100 Rows_examined: 50000
SET timestamp=1705315845;
SELECT * FROM orders WHERE user_id = 12345 AND status ='paid'ORDER BY created_at DESC LIMIT 20;

關鍵字段說明:Time是查詢執(zhí)行的時間;User@Host是執(zhí)行查詢的用戶和主機;Query_time是查詢實際執(zhí)行時間(秒),這是最核心的指標;Lock_time是等待鎖的時間;Rows_sent是返回給客戶端的行數(shù);Rows_examined是掃描的行數(shù),這個數(shù)字與Rows_sent的比值反映了查詢效率。

Rows_examined大而Rows_sent小,說明查詢在掃描大量數(shù)據(jù)后才找到符合條件的記錄,這是需要優(yōu)化的典型特征。高效的查詢應該讓Rows_examined盡可能接近Rows_sent。

1.3 使用 mysqldumpslow 分析慢查詢日志

直接閱讀原始慢查詢日志非常困難,mysqldumpslow工具可以對日志進行分析匯總:

# 安裝 MySQL 后即可使用
mysqldumpslow -t 10 /var/log/mysql/slow.log

# 參數(shù)說明:
# -t N   顯示前 N 條最慢的查詢
# -s C   按平均查詢時間排序(c=計數(shù),t=時間,l=鎖時間,r=返回行數(shù))
# -s S   按總查詢時間排序
# -s R   按平均掃描行數(shù)排序
# -a    不聚合相同的查詢
# -g PAT  只顯示匹配 pattern 的查詢

# 示例:顯示最慢的 10 條查詢
mysqldumpslow -t 10 -s t /var/log/mysql/slow.log

# 顯示掃描行數(shù)最多的查詢
mysqldumpslow -t 10 -s r /var/log/mysql/slow.log

# 顯示查詢次數(shù)最多的查詢
mysqldumpslow -t 10 -s c /var/log/mysql/slow.log

# 過濾特定表的查詢
mysqldumpslow -t 10 -g'orders'/var/log/mysql/slow.log

# 使用正則過濾
mysqldumpslow -t 10 -a -g'SELECT.*FROM.*WHERE'/var/log/mysql/slow.log

1.4 使用 pt-query-digest 進行深度分析

pt-query-digest是 Percona Toolkit 中的專業(yè)分析工具,比mysqldumpslow功能更強大:

# 安裝 Percona Toolkit
# Ubuntu/Debian
apt-get install percona-toolkit

# RHEL/CentOS
yum install percona-toolkit

# 基本用法
pt-query-digest /var/log/mysql/slow.log

# 輸出到文件
pt-query-digest /var/log/mysql/slow.log > /tmp/query_analysis.txt

# 只分析最近 24 小時的慢查詢(需要日志中有時間戳)
pt-query-digest --since'24h'/var/log/mysql/slow.log

# 分析特定時間的查詢
pt-query-digest --since'2024-01-15 1000'--until'2024-01-15 1200'/var/log/mysql/slow.log

# 輸出查詢響應時間分布
pt-query-digest --typegenlog /var/log/mysql/slow.log

pt-query-digest的輸出包括:查詢執(zhí)行時間分布直方圖;按響應時間排序的查詢列表;每種查詢的出現(xiàn)次數(shù)、平均執(zhí)行時間、掃描行數(shù)統(tǒng)計;查詢執(zhí)行計劃摘要;可能導致問題的查詢特征標記。

2 使用 EXPLAIN 分析查詢執(zhí)行計劃

2.1 EXPLAIN 基本用法

EXPLAIN是分析 SQL 查詢執(zhí)行計劃的核心命令,它告訴 MySQL 優(yōu)化器將如何執(zhí)行查詢,是排查慢查詢最重要的工具。

-- 基本格式
EXPLAINSELECT*FROMordersWHEREuser_id =12345;

-- 更詳細的輸出(包括擴展信息)
EXPLAINFORMAT=JSONSELECT*FROMordersWHEREuser_id =12345;

-- 查看 UPDATE、DELETE、INSERT 的執(zhí)行計劃
EXPLAINUPDATEordersSETstatus='shipped'WHEREorder_id =100;
EXPLAINDELETEFROMordersWHEREstatus='cancelled';

2.2 EXPLAIN 輸出字段詳解

EXPLAIN輸出的每一列都包含重要的優(yōu)化信息:

EXPLAINSELECTo.*, u.nameFROMorders o
JOINusersuONo.user_id = u.id
WHEREo.user_id =12345ANDo.status ='paid'
ORDERBYo.created_atDESCLIMIT20;

輸出示例:

+----+-------------+-------+------+-------------+------+--------+-------+---------------------+
| id | select_type| table |type| key     | rows | filtered| Extra |
+----+-------------+-------+------+-------------+------+--------+-------+
| 1 | SIMPLE   | o   | ref | idx_user  |  50 | 100.00| Using |
| 1 | SIMPLE   | u   | const| PRIMARY   |  1 | 100.00|    |
+----+-------------+-------+------+-------------+------+--------+-------+

id是查詢中 SELECT 的序號,復合查詢中 id 越大優(yōu)先級越高。select_type是查詢類型:SIMPLE 是簡單查詢(不含子查詢和 UNION);PRIMARY 是外層查詢;SUBQUERY 是子查詢;DERIVED 是派生表(FROM 中的子查詢);UNION 是 UNION 操作的查詢。table是涉及的表名。type是訪問類型,表示 MySQL 決定如何查找表中的行,這是最關鍵的字段之一。possible_keys是可供選擇的索引列表。key是實際選擇的索引。key_len是使用的索引長度。ref是與索引比較的列。rows是預計需要掃描的行數(shù)。filtered是按條件過濾后剩余的百分比。Extra是額外信息,包含優(yōu)化提示。

2.3 type 字段詳解

type字段反映了查詢的效率,從最好到最差依次是:system、const、eq_ref、ref、ref_or_null、index_merge、unique_subquery、index_subquery、range、index、ALL。

const是最優(yōu)的類型,表示只匹配一行,通常是通過主鍵或唯一索引查找。eq_ref表示通過主鍵或唯一索引關聯(lián)查詢,每個索引值只對應一行記錄。ref表示通過普通索引查找,返回所有匹配索引值的行。range表示使用索引范圍查詢(>、<、BETWEEN、IN 等)。index?表示全索引掃描,雖然比全表掃描好但仍然很慢。ALL?是最差的全表掃描,意味著沒有使用任何索引。

如果查詢的 type 是 ALL,說明沒有使用索引,這是需要重點優(yōu)化的對象。

-- 查看 type 為 ALL 的查詢(需要優(yōu)化的)
EXPLAINSELECT*FROMordersWHEREcreated_at >'2024-01-01';

-- 創(chuàng)建索引后,type 變?yōu)?range
CREATEINDEXidx_orders_created_atONorders(created_at);
EXPLAINSELECT*FROMordersWHEREcreated_at >'2024-01-01';

2.4 Extra 字段詳解

Extra字段包含 MySQL 解析查詢的額外信息,常見的值及其含義:

Using filesort表示 MySQL 無法利用索引完成排序,需要額外的排序操作。這是需要優(yōu)化的信號。Using temporary表示查詢需要創(chuàng)建臨時表來存儲結果,通常發(fā)生在 ORDER BY 和 GROUP BY 操作中。Using index表示使用了覆蓋索引,查詢只需要索引就能完成,不需要回表。Using index condition表示使用了索引下推優(yōu)化。Using where表示在存儲引擎層使用 WHERE 條件過濾。Using join buffer表示使用了連接緩存。

-- 出現(xiàn) Using filesort,需要優(yōu)化排序
EXPLAINSELECT*FROMordersWHEREuser_id =123ORDERBYcreated_atDESC;

-- 優(yōu)化方案:利用索引消除 filesort
CREATEINDEXidx_orders_user_createdONorders(user_id, created_atDESC);

2.5 使用 EXPLAIN ANALYZE(MySQL 8.0+)

MySQL 8.0 引入了EXPLAIN ANALYZE,它不僅顯示執(zhí)行計劃,還實際執(zhí)行查詢并報告真實的統(tǒng)計數(shù)據(jù):

EXPLAINANALYZE
SELECTo.*, u.nameFROMorders o
JOINusersuONo.user_id = u.id
WHEREo.user_id =12345ANDo.status ='paid'
ORDERBYo.created_atDESCLIMIT20;

輸出包括預估的 rows 和實際執(zhí)行的 rows,以及實際執(zhí)行時間。通過對比預估和實際,可以發(fā)現(xiàn)統(tǒng)計信息過時或執(zhí)行計劃錯誤的問題。

3 索引的創(chuàng)建與優(yōu)化

3.1 索引原理概述

理解索引的原理是正確使用索引的前提。MySQL 中最常用的是 B+Tree 索引,它將數(shù)據(jù)按照 B+Tree 數(shù)據(jù)結構組織,每個葉子節(jié)點包含所有數(shù)據(jù)(聚簇索引)或數(shù)據(jù)指針(非聚簇索引)。

B+Tree 索引的特點:所有葉子節(jié)點在同一層級,樹的高度低,查詢效率穩(wěn)定;葉子節(jié)點之間通過鏈表連接,支持范圍查詢;每個節(jié)點可以存儲多個鍵值,寬度大,層級淺。

索引的優(yōu)勢:大幅減少查詢需要掃描的數(shù)據(jù)量;避免排序和臨時表生成;支持索引覆蓋掃描,直接返回結果。

索引的代價:占用額外的磁盤空間;寫入操作(INSERT、UPDATE、DELETE)需要維護索引,降低寫入性能;創(chuàng)建索引需要加鎖,可能阻塞其他操作。

3.2 創(chuàng)建索引的原則

創(chuàng)建索引需要遵循以下原則:

選擇區(qū)分度高的列創(chuàng)建索引。區(qū)分度指列中不重復值的比例,比例越高,索引效率越好。使用SELECT COUNT(DISTINCT column) / COUNT(*) FROM table計算區(qū)分度。

-- 查看列的區(qū)分度
SELECTCOUNT(DISTINCTstatus) /COUNT(*)FROMorders;
SELECTCOUNT(DISTINCTuser_id) /COUNT(*)FROMorders;

-- status 區(qū)分度低(只有幾種狀態(tài)),user_id 區(qū)分度高
-- 應該為 user_id 創(chuàng)建索引,而不是 status

復合索引遵循最左前綴原則。復合索引INDEX idx(a, b, c)可以支持WHERE a = ?、WHERE a = ? AND b = ?、WHERE a = ? AND b = ? AND c = ?的查詢,但不支持WHERE b = ?或WHERE c = ?的查詢。

-- 創(chuàng)建復合索引
CREATEINDEXidx_orders_user_statusONorders(user_id,status, created_at);

-- 這些查詢可以使用該索引
SELECT*FROMordersWHEREuser_id =123;
SELECT*FROMordersWHEREuser_id =123ANDstatus='paid';
SELECT*FROMordersWHEREuser_id =123ANDstatus='paid'ANDcreated_at >'2024-01-01';

-- 這個查詢無法使用該索引(最左前綴不滿足)
SELECT*FROMordersWHEREstatus='paid';

為主鍵和唯一約束創(chuàng)建唯一索引。唯一索引保證列值的唯一性,同時提供快速的唯一性查找。

3.3 索引創(chuàng)建實戰(zhàn)

根據(jù)慢查詢日志和 EXPLAIN 分析結果,為慢查詢創(chuàng)建合適的索引:

-- 分析慢查詢
-- SELECT * FROM orders WHERE user_id = 12345 AND status = 'paid' ORDER BY created_at DESC LIMIT 20;

-- 根據(jù) WHERE 條件和 ORDER BY 創(chuàng)建復合索引
-- 1. 區(qū)分度高的列靠前:user_id > status
-- 2. ORDER BY 的列需要與 WHERE 條件一起創(chuàng)建索引
-- 3. 需要倒序排序,如果是 MySQL 8.0+ 可以創(chuàng)建倒序索引

CREATEINDEXidx_orders_user_status_createdONorders(user_id,status, created_atDESC);

-- 如果是 MySQL 5.7,需要創(chuàng)建兩個索引
CREATEINDEXidx_orders_user_statusONorders(user_id,status);
CREATEINDEXidx_orders_user_createdONorders(user_id, created_atDESC);

3.4 索引使用注意事項

避免在索引列上使用函數(shù)或進行計算,這會導致索引失效:

-- 索引失效
SELECT*FROMordersWHEREYEAR(created_at) =2024;
SELECT*FROMordersWHEREcreated_at +INTERVAL1DAY>NOW();

-- 正確的做法
SELECT*FROMordersWHEREcreated_at >='2024-01-01'ANDcreated_at 

避免使用 LIKE 開頭是通配符的查詢:

-- 索引失效
SELECT*FROMordersWHEREorder_noLIKE'%123%';
SELECT*FROMordersWHEREorder_noLIKE'%123';

-- 可以使用索引
SELECT*FROMordersWHEREorder_noLIKE'ABC123%';

數(shù)據(jù)類型要匹配:

-- 如果 user_id 是 INT 類型
-- 錯誤:字符串與數(shù)字比較
SELECT*FROMordersWHEREuser_id ='12345';

-- 正確:使用相同類型
SELECT*FROMordersWHEREuser_id =12345;

3.5 查看索引使用情況

創(chuàng)建索引后,需要確認索引是否被使用:

-- 查看表的索引
SHOWINDEXFROMorders;

-- 使用 EXPLAIN 檢查是否使用索引
EXPLAINSELECT*FROMordersWHEREuser_id =12345;

-- 查看索引的基數(shù)(Cardinality,反映區(qū)分度)
SHOWTABLESTATUSLIKE'orders';

-- MySQL 8.0+ 使用 INDEX_STATISTICS
SELECT*FROMmysql.index_statisticsWHEREtable_name ='orders';

4 SQL 語句優(yōu)化

4.1 常見低效 SQL 模式

避免 SELECT *,只查詢需要的列:

-- 低效:返回所有列
SELECT*FROMordersWHEREorder_id =12345;

-- 高效:只查詢需要的列
SELECTorder_id, user_id,status, total_amount, created_at
FROMordersWHEREorder_id =12345;

使用 LIMIT 限制返回行數(shù):

-- 低效:沒有 LIMIT,可能返回大量數(shù)據(jù)
SELECT*FROMordersWHEREuser_id =12345ORDERBYcreated_atDESC;

-- 高效:使用 LIMIT
SELECT*FROMordersWHEREuser_id =12345ORDERBYcreated_atDESCLIMIT20;

分解大查詢,減少單次查詢的掃描范圍:

-- 低效:一個復雜查詢處理大量數(shù)據(jù)
SELECTo.*, u.*, p.*
FROMorders o
JOINusersuONo.user_id = u.id
JOINproducts pONo.product_id = p.id
WHEREo.created_at >'2024-01-01';

-- 高效:分步處理,先篩選出符合條件的訂單,再關聯(lián)其他表
SELECT*FROMordersWHEREcreated_at >'2024-01-01'LIMIT1000;
-- 然后用 IN 子句關聯(lián)用戶和產品
SELECTu.*FROMusersWHEREidIN(SELECTDISTINCTuser_idFROMordersWHEREcreated_at >'2024-01-01');

4.2 優(yōu)化 ORDER BY 和 GROUP BY

ORDER BY 使用索引可以避免 filesort:

-- 創(chuàng)建復合索引使 ORDER BY 使用索引
CREATEINDEXidx_orders_user_status_createdONorders(user_id,status, created_atDESC);

-- 這個查詢可以使用索引排序
SELECT*FROMorders
WHEREuser_id =123
ORDERBYstatus, created_atDESC
LIMIT20;

GROUP BY 同樣可以利用索引:

-- 如果查詢經常按時間分組統(tǒng)計,創(chuàng)建按時間的索引
CREATEINDEXidx_orders_created_atONorders(created_at);

-- 分組查詢
SELECTDATE(created_at),COUNT(*),SUM(total_amount)
FROMorders
GROUPBYDATE(created_at);

4.3 優(yōu)化 JOIN 操作

確保 JOIN 條件有索引:

-- orders.user_id 和 users.id 都應該有索引
CREATEINDEXidx_orders_user_idONorders(user_id);
CREATEINDEXidx_users_idONusers(id);

-- 使用 EXPLAIN 檢查 JOIN 類型
EXPLAINSELECTo.*, u.name
FROMorders o
JOINusersuONo.user_id = u.id
WHEREo.user_id =12345;

小表驅動大表(讓小表先過濾,減少被驅動表的掃描次數(shù)):

-- orders 表有 1000 萬條記錄,users 表有 10 萬條記錄
-- 正確:用小表驅動大表
SELECTo.*, u.name
FROMusersu
JOINorders oONo.user_id = u.id
WHEREu.status ='vip';

-- 可能效率更低
SELECTo.*, u.name
FROMorders o
JOINusersuONo.user_id = u.id
WHEREu.status ='vip';

4.4 使用 EXISTS 替代 IN

-- 子查詢表很大的情況下,IN 的效率可能很低
SELECT*FROMorders
WHEREuser_idIN(SELECTidFROMusersWHEREstatus='vip');

-- 使用 EXISTS 通常更高效
SELECT*FROMorders o
WHEREEXISTS(SELECT1FROMusersuWHEREu.id = o.user_idANDu.status ='vip');

5 數(shù)據(jù)庫配置優(yōu)化

5.1 關鍵配置參數(shù)

MySQL 的配置文件對性能有重大影響。關鍵參數(shù)包括:

[mysqld]
# InnoDB 緩沖池大小,通常設置為可用內存的 70-80%
innodb_buffer_pool_size = 12G

# 日志文件大小
innodb_log_file_size = 1G

# 刷新日志的策略(影響寫入性能和數(shù)據(jù)安全)
innodb_flush_log_at_trx_commit = 1

# 最大連接數(shù)
max_connections = 500

# 查詢緩存(MySQL 8.0 已移除)
query_cache_size = 0
query_cache_type = 0

# 臨時表和內存表大小
tmp_table_size = 256M
max_heap_table_size = 256M

# 慢查詢日志
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1

# 記錄未使用索引的查詢
log_queries_not_using_indexes = 1

5.2 InnoDB 緩沖池優(yōu)化

InnoDB 緩沖池是 InnoDB 最重要的性能參數(shù),它緩存表數(shù)據(jù)和索引。緩沖池越大,可以緩存的數(shù)據(jù)越多,磁盤 I/O 越少。

-- 查看緩沖池使用情況
SHOWSTATUSLIKE'Innodb_buffer_pool%';

-- 查看緩沖池大小配置
SHOWVARIABLESLIKE'innodb_buffer_pool_size';

-- 動態(tài)調整緩沖池大?。∕ySQL 5.7+)
SETGLOBALinnodb_buffer_pool_size =12873741824; -- 12GB

-- 設置緩沖池實例數(shù)量(建議 CPU 核心數(shù))
innodb_buffer_pool_instances = 8

-- 預熱緩沖池(數(shù)據(jù)庫重啟后自動加載熱數(shù)據(jù)到內存)
innodb_buffer_pool_load_at_startup = 1

5.3 連接數(shù)管理

連接數(shù)過多會導致資源耗盡,連接數(shù)過少會限制并發(fā)能力。

-- 查看當前連接數(shù)
SHOWSTATUSLIKE'Threads_connected';
SHOWSTATUSLIKE'Max_used_connections';

-- 查看最大連接數(shù)
SHOWVARIABLESLIKE'max_connections';

-- 調整最大連接數(shù)
SETGLOBALmax_connections =1000;

-- 查看連接來源
SHOWPROCESSLIST;
SHOWFULLPROCESSLIST;

-- 殺掉長時間空閑的連接
SELECTCONCAT('KILL ',id,';')
FROMinformation_schema.processlist
WHERECommand ='Sleep'ANDTime>3600;

6 慢查詢優(yōu)化實戰(zhàn)案例

6.1 案例一:分頁查詢優(yōu)化

后臺管理系統(tǒng)中常見的需求是分頁查詢訂單列表:

-- 低效的深分頁查詢(頁面越大越慢)
SELECT*FROMordersORDERBYorder_idDESCLIMIT1000000,20;

-- 問題分析:
-- 1. LIMIT offset 很大時,MySQL 需要掃描 offset + limit 條記錄
-- 2. rows_examined 會非常大
EXPLAINSELECT*FROMordersORDERBYorder_idDESCLIMIT1000000,20;

-- 優(yōu)化方案一:使用游標分頁(基于上一頁最后一條記錄的 ID)
SELECT*FROMorders
WHEREorder_id 

6.2 案例二:統(tǒng)計查詢優(yōu)化

需要統(tǒng)計每天的訂單數(shù)量和金額:

-- 低效:實時計算,每次查詢都掃描全表
SELECTDATE(created_at)ASday,
   COUNT(*)ASorder_count,
   SUM(total_amount)AStotal_amount
FROMorders
WHEREcreated_at >='2024-01-01'
GROUPBYDATE(created_at);

-- 優(yōu)化方案一:使用匯總表
CREATETABLEorders_daily_summary (
  stat_dateDATEPRIMARYKEY,
  order_countINTNOTNULLDEFAULT0,
  total_amountDECIMAL(15,2)NOTNULLDEFAULT0,
  updated_atTIMESTAMPDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP
);

-- 定期匯總(可以使用事件或 cron 任務)
INSERTINTOorders_daily_summary (stat_date, order_count, total_amount)
SELECTDATE(created_at),COUNT(*),SUM(total_amount)
FROMorders
WHEREDATE(created_at) ='2024-01-15'
GROUPBYDATE(created_at)
ONDUPLICATEKEYUPDATE
  order_count =VALUES(order_count),
  total_amount =VALUES(total_amount);

-- 查詢匯總表
SELECT*FROMorders_daily_summaryWHEREstat_date >='2024-01-01';

6.3 案例三:模糊搜索優(yōu)化

用戶表需要支持按用戶名模糊搜索:

-- 低效:LIKE 開頭是通配符導致全表掃描
SELECT*FROMusersWHEREnameLIKE'%zhang%';

-- 優(yōu)化方案一:使用全文索引(MySQL 5.6+)
ALTERTABLEusersADDFULLTEXTINDEXft_users_name(name);

SELECT*FROMusersWHEREMATCH(name) AGAINST('zhang');

-- 優(yōu)化方案二:使用 Elasticsearch 等專業(yè)搜索引擎
-- 適用于模糊搜索需求復雜、對性能要求高的場景

-- 優(yōu)化方案三:使用前綴索引(適用于前綴固定的場景)
CREATEINDEXidx_users_name_prefixONusers(name(10));

-- 如果 name 通常以姓開頭
SELECT*FROMusersWHEREnameLIKE'zhang%'; -- 可以使用索引

7 監(jiān)控與預防

7.1 持續(xù)監(jiān)控慢查詢

使用 pt-query-digest 定期分析慢查詢日志:

#!/bin/bash
# 每天凌晨分析昨天的慢查詢日志

DATE=$(date -d"yesterday"+%Y-%m-%d)
SLOW_LOG="/var/log/mysql/slow.log"
REPORT="/var/log/mysql/slow_query_report_${DATE}.txt"

pt-query-digest --since"$(date -d 'yesterday 0000' +%s)seconds"
        --until"$(date -d 'yesterday 2359' +%s)seconds"
        --report-format=query_report 
       $SLOW_LOG>$REPORT

# 如果有新的慢查詢,發(fā)送告警
if[ -s"$REPORT"];then
  count=$(grep -c"Query"$REPORT||true)
 if["$count"-gt 10 ];then
   echo"Found$countslow queries in the report"| mail -s"Slow Query Alert"ops@example.com
 fi
fi

7.2 使用 Performance Schema

MySQL 5.6+ 提供了 Performance Schema,可以實時監(jiān)控查詢性能:

-- 啟用相關的 instrument 和 consumer
UPDATEperformance_schema.setup_instruments
SETENABLED ='YES'
WHERENAMELIKE'statement/%';

UPDATEperformance_schema.setup_consumers
SETENABLED ='YES'
WHERENAMELIKE'events_statements%';

-- 查看當前最慢的查詢
SELECT
  DIGEST,
  COUNT_STAR,
  SUM_TIMER_WAIT /1000000000000AStotal_time_sec,
  AVG_TIMER_WAIT /1000000000000ASavg_time_sec,
  SUM_ROWS_EXAMINED,
  SUM_ROWS_SENT,
 SUBSTR(DIGEST_TEXT,1,100)ASquery_sample
FROMperformance_schema.events_statements_summary_by_digest
ORDERBYSUM_TIMER_WAITDESC
LIMIT10;

7.3 建立慢查詢治理流程

生產環(huán)境的慢查詢治理應該成為日常工作的一部分:

日常監(jiān)控:每天檢查新增的慢查詢

分析根因:使用 EXPLAIN 分析執(zhí)行計劃

制定優(yōu)化方案:索引優(yōu)化、SQL 改寫、配置調整

上線驗證:確認優(yōu)化效果

歸檔記錄:記錄問題和解決方案,形成知識庫

8 結論

數(shù)據(jù)庫慢查詢優(yōu)化是一個系統(tǒng)性的工作,需要綜合運用多種方法和工具。

首先,通過慢查詢日志發(fā)現(xiàn)慢查詢,使用 mysqldumpslow 或 pt-query-digest 進行分析;其次,使用 EXPLAIN 分析執(zhí)行計劃,找出性能瓶頸;然后,根據(jù)分析結果選擇優(yōu)化手段:創(chuàng)建合適的索引、重寫 SQL 語句、調整數(shù)據(jù)庫配置;最后,通過持續(xù)監(jiān)控防止慢查詢復發(fā)。

加索引只是優(yōu)化手段之一,不是萬能藥。正確的優(yōu)化思路是:先分析,再決策,最后實施。不加分析的盲目加索引可能適得其反。

運維工程師應該掌握的慢查詢排查技能:開啟和配置慢查詢日志;使用 EXPLAIN 分析執(zhí)行計劃;創(chuàng)建和分析索引;識別常見的低效 SQL 模式;根據(jù)業(yè)務特點制定優(yōu)化方案。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 數(shù)據(jù)庫

    關注

    7

    文章

    4083

    瀏覽量

    68538
  • Oracle
    +關注

    關注

    2

    文章

    308

    瀏覽量

    38947
  • MySQL
    +關注

    關注

    1

    文章

    931

    瀏覽量

    29748

原文標題:數(shù)據(jù)庫慢查詢怎么查?別再只會讓開發(fā)加索引

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    深入優(yōu)化DB2 數(shù)據(jù)庫的五個最佳實踐

    深入優(yōu)化DB2 數(shù)據(jù)庫的五個最佳實踐   結構化查詢語言(SQL)對于關系型DBMS是把雙刃劍,利弊參半。因為從關系型數(shù)據(jù)庫檢索任何
    發(fā)表于 01-27 13:28 ?1125次閱讀

    保護MySQL數(shù)據(jù)倉庫的最佳實踐

    數(shù)據(jù)倉庫中最常見的數(shù)據(jù)庫管理系統(tǒng)可能就是開源的MySQL數(shù)據(jù)庫。以下5個小技巧重點介紹了一些保護MySQL
    發(fā)表于 09-27 14:10 ?0次下載

    TreeView Mysql查詢數(shù)據(jù)庫的詳細資料合集免費下載

    本文檔的主要內容詳細介紹的是TreeView Mysql查詢數(shù)據(jù)庫的詳細資料合集免費下載。
    發(fā)表于 12-12 08:00 ?0次下載
    TreeView <b class='flag-5'>Mysql</b><b class='flag-5'>查詢</b><b class='flag-5'>數(shù)據(jù)庫</b>的詳細資料合集免費下載

    華為云數(shù)據(jù)庫-RDS for MySQL數(shù)據(jù)庫

    華為云數(shù)據(jù)庫-RDS for MySQL數(shù)據(jù)庫 華為云數(shù)據(jù)庫作為華為云的一款數(shù)據(jù)庫產品,它主要是以MyS
    的頭像 發(fā)表于 10-27 11:06 ?2470次閱讀

    MySQL數(shù)據(jù)庫管理與應用

    MySQL數(shù)據(jù)庫管理與應用 MySQL是一種廣泛使用的關系型數(shù)據(jù)庫管理系統(tǒng),被認為是最流行和最常見的開源數(shù)據(jù)庫之一。它可以被用于多種不同的應
    的頭像 發(fā)表于 08-28 17:15 ?1941次閱讀

    MySQL數(shù)據(jù)庫基礎知識

    的基礎知識,包括其架構、數(shù)據(jù)類型、表操作、查詢語句和數(shù)據(jù)導入導出等方面。 MySQL 數(shù)據(jù)庫架構 MyS
    的頭像 發(fā)表于 11-21 11:09 ?2001次閱讀

    mysql數(shù)據(jù)庫基礎命令

    MySQL是一個流行的關系型數(shù)據(jù)庫管理系統(tǒng),經常用于存儲、管理和操作數(shù)據(jù)。在本文中,我們將詳細介紹MySQL的基礎命令,并提供與每個命令相關的詳細解釋。 登錄
    的頭像 發(fā)表于 12-06 10:56 ?1547次閱讀

    數(shù)據(jù)庫數(shù)據(jù)恢復—MYSQL數(shù)據(jù)庫ibdata1文件損壞的數(shù)據(jù)恢復案例

    mysql數(shù)據(jù)庫故障: mysql數(shù)據(jù)庫文件ibdata1、MYI、MYD損壞。 故障表現(xiàn):1、數(shù)據(jù)庫無法進行
    的頭像 發(fā)表于 12-09 11:05 ?1390次閱讀

    數(shù)據(jù)庫數(shù)據(jù)恢復—Mysql數(shù)據(jù)庫表記錄丟失的數(shù)據(jù)恢復流程

    Mysql數(shù)據(jù)庫故障: Mysql數(shù)據(jù)庫表記錄丟失。 Mysql數(shù)據(jù)庫故障表現(xiàn): 1、
    的頭像 發(fā)表于 12-16 11:05 ?1347次閱讀
    <b class='flag-5'>數(shù)據(jù)庫</b><b class='flag-5'>數(shù)據(jù)</b>恢復—<b class='flag-5'>Mysql</b><b class='flag-5'>數(shù)據(jù)庫</b>表記錄丟失的<b class='flag-5'>數(shù)據(jù)</b>恢復流程

    MySQL數(shù)據(jù)庫的安裝

    MySQL數(shù)據(jù)庫的安裝 【一】各種數(shù)據(jù)庫的端口 MySQL :3306 Redis :6379 MongoDB :27017 Django :8000 flask :5000 【二】
    的頭像 發(fā)表于 01-14 11:25 ?1242次閱讀
    <b class='flag-5'>MySQL</b><b class='flag-5'>數(shù)據(jù)庫</b>的安裝

    MySQL數(shù)據(jù)庫是什么

    MySQL數(shù)據(jù)庫是一種 開源的關系型數(shù)據(jù)庫管理系統(tǒng)(RDBMS) ,由瑞典MySQL AB公司開發(fā),后被Oracle公司收購。它通過結構化查詢
    的頭像 發(fā)表于 05-23 09:18 ?1444次閱讀

    企業(yè)級MySQL數(shù)據(jù)庫管理指南

    在當今數(shù)字化時代,MySQL作為全球最受歡迎的開源關系型數(shù)據(jù)庫,承載著企業(yè)核心業(yè)務數(shù)據(jù)的存儲與處理。作為數(shù)據(jù)庫管理員(DBA),掌握MySQL
    的頭像 發(fā)表于 07-09 09:50 ?887次閱讀

    MySQL查詢終極優(yōu)化指南

    作為一名在生產環(huán)境摸爬滾打多年的運維工程師,我見過太多因為查詢導致的線上故障。今天分享一套經過實戰(zhàn)檢驗的MySQL查詢分析與索引優(yōu)化方法
    的頭像 發(fā)表于 08-13 15:55 ?953次閱讀

    MySQL數(shù)據(jù)庫查詢分析與優(yōu)化實戰(zhàn)

    在討論MySQL查詢之前,需要先明確一個關鍵前提:什么是查詢? 不同業(yè)務場景下,
    的頭像 發(fā)表于 04-02 09:38 ?170次閱讀

    MySQL查詢調優(yōu)指南

    MySQL查詢數(shù)據(jù)庫性能問題的最常見原因。當一條SQL語句執(zhí)行超過1秒時,就可能影響用戶體驗;超過10秒時,通常會收到用戶投訴;而超過30秒的
    的頭像 發(fā)表于 04-09 10:01 ?179次閱讀
    湘阴县| 读书| 准格尔旗| 深圳市| 利津县| 上杭县| 七台河市| 富裕县| 宁武县| 伊通| 太保市| 绥阳县| 武汉市| 宿迁市| 油尖旺区| 县级市| 瑞金市| 榆社县| 昂仁县| 庆云县| 承德县| 榆林市| 清镇市| 磐安县| 锡林郭勒盟| 中牟县| 阜康市| 分宜县| 丘北县| 洮南市| 河池市| 大化| 仙桃市| 嘉义市| 北安市| 阿坝县| 井陉县| 铜鼓县| 凤庆县| 邢台市| 德州市|