1.如何定位慢查詢?
定位慢查詢主要依靠 MySQL 的慢查詢日志配合工具如 pt-query-digest ,mysqldumpslow 進行分析,或者通過 performance_schema 進行實時監控,進一步可以使用 EXPLAIN 分析執行計劃。
-> 開啟慢查詢日志
-- 查看慢查詢日志是否開啟:
SHOW VARIABLES LIKE 'slow_query_log%';
-- 開啟慢查詢日志(立即生效)
SET GLOBAL slow_query_log = 'ON';
-- 設置慢查詢時間閾值為 1 秒:
SET GLOBAL long_query_time = 1;
-- 設置慢查詢日志文件路徑(可選)
SET GLOBAL slow_query_log_file = '/var/log/mysql/mysql-slow.log';
-- 查看慢查詢文件位置:
SHOW VARIABLES LIKE 'slow_query_log_file';
-- 查看慢查詢總數:
SHOW GLOBAL STATUS LIKE 'Slow_queries';
-> 收集慢查詢日志(慢于 long_query_time 的語句)
-> 使用工具提取 Top N 慢 SQL(如 pt-query-digest)
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
pt-query-digest /var/log/mysql/slow.log
-> 對具體 SQL 使用 EXPLAIN 或 EXPLAIN ANALYZE 分析執行計劃
EXPLAIN SELECT * FROM user WHERE name LIKE '%abc%';
EXPLAIN ANALYZE SELECT * FROM user WHERE id = 123;
-> 判斷是否索引失效 / 全表掃描 / 關聯順序不佳等
-> 優化 SQL 或加索引,重復測試
2.一個 SQL 語句執行很慢,如何分析 ?
我用 EXPLAIN 分析 SQL 時,重點關注以下幾個字段:
type 是訪問類型,性能最好的是 const(主鍵查單條)、eq_ref/ref(使用索引查找),次一點的是 range(范圍掃描),最差的是 ALL(全表掃描),index(全索引掃描);
key 表示實際使用的索引,若為 NULL 則說明沒有用到索引,通常性能較差,如果 possible_key 有值,而 key 為 null,證明有索引可能能用但是沒命中,就需要考慮是什么原因導致了索引失效;
rows 代表預估掃描的行數,數字越小越好,過大說明掃描量大,效率低;
Extra 字段里如果出現 Using filesort 或 Using temporary,說明使用了額外的排序或臨時表,通常是性能瓶頸;如果看到 Using index 則說明是覆蓋索引,性能很好,避免了回表;
綜上,通過這些字段可以判斷 SQL 是否命中索引,掃描量是否合理,以及是否存在額外開銷,從而指導優化方案。
3.什么情況下索引會失效 ?
1.違反最左前綴匹配原則: 復合索引(多列索引)只有從最左邊的列開始按順序使用,跳過最左列會失效。
2.使用了函數: 如 WHERE YEAR(create_time) = 2023
,索引失效,因為函數包裹了列,MySQL 無法用索引直接匹配。
3. 使用了通配符 %
開頭的 LIKE:LIKE '%abc'
無法使用索引,因為前綴不確定,但 LIKE 'abc%'
是可以走索引的。
4. 隱式類型轉換: 查詢條件的數據類型與索引列類型不匹配,會導致索引失效。
5. OR 條件沒有覆蓋所有列的索引:如果只用部分索引,另一部分條件需要全表掃描,這樣部分索引的使用反而可能加重了整體掃描成本。
6. 使用了 NOT 或 <> 等否定條件: 例如 WHERE col <> 1
,MySQL一般無法利用索引。
7. 不等式比較符號(<, >, !=)后面的列索引不能用: 在復合索引中,使用不等式后,后續的列索引無法使用。 復合索引中,遇到范圍查詢(如 b > 10
)后,索引只能定位該范圍,后續列(如 c
)索引失效,需回表過濾;而對同一列的多范圍條件(如 b > 10 AND b < 20
)則仍能利用索引縮小掃描范圍。
4.MYSQL 超大分頁怎么處理 ?
超大分頁避免使用 LIMIT offset, size
,改用基于唯一索引的范圍查詢(如 WHERE id > last_id LIMIT size
)實現延遲關聯,極大提升查詢效率。或者分表分庫通過拆分數據減少單表數據量。亦或者熱點數據可考慮緩存。
5.談談你對 SQL 的優化的經驗
1. 合理設計索引
根據查詢條件設計覆蓋索引,盡量減少回表。
避免冗余和過多索引,減少寫入負擔。
注意復合索引最左前綴原則,盡量讓查詢條件匹配索引順序。
2. 優化查詢語句
避免 SELECT *
,只查需要的列。
避免在索引列上使用函數或表達式,保證索引可用。
拆分復雜查詢,避免過多 JOIN
或子查詢。
對 OR
語句可拆成多條 UNION
查詢。
3. 合理使用分頁
避免大偏移量分頁,使用基于唯一索引的延遲關聯分頁。
熱點數據可考慮緩存。
4. 分析執行計劃
使用 EXPLAIN
分析查詢路徑,重點看 type
、possible_keys
、key
、rows
和 Extra
字段。
確認索引是否被使用,避免全表掃描。
注意是否有 Using filesort
或 Using temporary
,這可能是性能瓶頸。
5.數據量與分區
對超大表考慮分區或分表,降低單表壓力。
歸檔歷史數據,減少熱點數據量。