最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL慢查詢分析與優(yōu)化全過(guò)程

 更新時(shí)間:2026年05月21日 08:27:06   作者:WL_Aurora  
本文介紹了MySQL慢查詢優(yōu)化的完整閉環(huán),從開啟慢查詢?nèi)罩?、使用pt-query-digest定位TOP慢SQL、借助EXPLAIN診斷執(zhí)行計(jì)劃、給出優(yōu)化案例,到搭建Prometheus+Grafana監(jiān)控體系,針對(duì)全表掃描、深分頁(yè)、隱式類型轉(zhuǎn)換、OR條件和聚合統(tǒng)計(jì)等個(gè)常見問(wèn)題,需要的朋友可以參考下

摘要:慢查詢是 MySQL 性能問(wèn)題中最常見、影響最大的殺手。本文從慢查詢?nèi)罩镜呐渲瞄_啟講起,通過(guò) pt-query-digest 定位 TOP 慢 SQL,結(jié)合 EXPLAIN 診斷執(zhí)行計(jì)劃,給出 5 個(gè)真實(shí)優(yōu)化案例(從全表掃描到覆蓋索引、從深分頁(yè)到子查詢改寫),最后搭建 Prometheus + Grafana 監(jiān)控體系,形成完整的慢查詢優(yōu)化閉環(huán)。全文包含實(shí)戰(zhàn)命令和性能對(duì)比數(shù)據(jù),建議收藏。

一、慢查詢優(yōu)化的完整閉環(huán)

慢查詢優(yōu)化不是一次性任務(wù),而是一個(gè)持續(xù)迭代的 PDCA 閉環(huán):

發(fā)現(xiàn) → 定位 → 診斷 → 優(yōu)化 → 驗(yàn)證 → 監(jiān)控 → 再回到發(fā)現(xiàn)

MySQL 查詢執(zhí)行流程如下:客戶端發(fā)送 SQL → 解析器解析 → 預(yù)處理器處理 → 查詢優(yōu)化器生成執(zhí)行計(jì)劃 → 查詢執(zhí)行引擎調(diào)用存儲(chǔ)引擎 → 返回結(jié)果。

理解這個(gè)流程對(duì)診斷慢查詢至關(guān)重要:優(yōu)化器選擇的執(zhí)行計(jì)劃直接決定了查詢效率,而執(zhí)行計(jì)劃又依賴于索引統(tǒng)計(jì)信息和成本估算。

二、第一步:發(fā)現(xiàn)慢查詢

2.1 開啟慢查詢?nèi)罩荆⊿low Query Log)

慢查詢?nèi)罩臼?MySQL 內(nèi)置的慢 SQL 記錄機(jī)制,建議生產(chǎn)環(huán)境必開。

-- 查看當(dāng)前配置
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

-- 動(dòng)態(tài)開啟(無(wú)需重啟,但重啟后失效)
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
SET GLOBAL long_query_time = 1;  -- 超過(guò) 1 秒視為慢查詢

-- 記錄未使用索引的查詢(強(qiáng)烈建議開啟)
SET GLOBAL log_queries_not_using_indexes = 'ON';

永久生效配置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
log_output = FILE  -- 或 TABLE,記錄到 mysql.slow_log 表

2.2 使用 Performance Schema(MySQL 5.6+)

Performance Schema 提供更精細(xì)的語(yǔ)句級(jí)性能數(shù)據(jù),無(wú)需寫日志文件。

-- 開啟 Statement 監(jiān)控
UPDATE performance_schema.setup_consumers 
SET ENABLED = 'YES' WHERE NAME LIKE '%statements%';

-- 查看耗時(shí) TOP 10 的 SQL
SELECT 
    DIGEST_TEXT AS query,
    COUNT_STAR AS exec_count,
    ROUND(SUM_TIMER_WAIT/1000000000000, 2) AS total_latency_sec,
    ROUND(AVG_TIMER_WAIT/1000000000000, 4) AS avg_latency_sec,
    ROUND(MAX_TIMER_WAIT/1000000000000, 4) AS max_latency_sec
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 10;

Performance Schema 的數(shù)據(jù)實(shí)時(shí)在內(nèi)存中維護(hù),適合需要即時(shí)分析的場(chǎng)景,但重啟后數(shù)據(jù)會(huì)丟失。

2.3 使用 sys 系統(tǒng)庫(kù)(MySQL 5.7+)

sys 庫(kù)基于 Performance Schema 提供了更友好的視圖:

-- 查看全表掃描次數(shù)最多的 SQL
SELECT * FROM sys.statements_with_full_table_scans 
ORDER BY rows_examined DESC LIMIT 10;

-- 查看執(zhí)行次數(shù)最多且平均耗時(shí)高的 SQL
SELECT * FROM sys.statements_with_runtimes_in_95th_percentile;

-- 查看使用臨時(shí)表和文件排序的 SQL
SELECT * FROM sys.statements_with_sorting 
ORDER BY rows_sorted DESC LIMIT 10;

三、第二步:定位 TOP 慢 SQL

3.1 pt-query-digest:慢日志分析神器

pt-query-digest 是 Percona Toolkit 中的慢查詢分析工具,能將混亂的慢日志整理成清晰的排名報(bào)告。

安裝

# Ubuntu/Debian
apt-get install percona-toolkit
# CentOS/RHEL
yum install percona-toolkit
# 或下載源碼包
wget https://www.percona.com/downloads/percona-toolkit/3.5.5/binary/tarball/percona-toolkit-3.5.5_x86_64.tar.gz

基本用法

# 分析慢查詢?nèi)罩?,輸出到文?
pt-query-digest /var/log/mysql/slow.log > slow_report.txt
# 只顯示前 20 條(默認(rèn)按總耗時(shí)排序)
pt-query-digest --limit 20 /var/log/mysql/slow.log
# 過(guò)濾只分析最近 1 小時(shí)的日志
pt-query-digest --since "1h" /var/log/mysql/slow.log
# 分析特定數(shù)據(jù)庫(kù)的慢查詢
pt-query-digest --filter '$event->{db} eq "mydb"' /var/log/mysql/slow.log
# 直接分析 Processlist(實(shí)時(shí)分析)
pt-query-digest --processlist h=localhost,u=root,p=password

3.2 pt-query-digest 報(bào)告核心指標(biāo)解讀

報(bào)告頭部 Overall statistics 匯總了日志整體情況:

指標(biāo)含義優(yōu)化意義
Exec timeSQL 總執(zhí)行時(shí)間找出時(shí)間殺手
Lock time等待鎖的時(shí)間高說(shuō)明有鎖競(jìng)爭(zhēng)
Rows sent返回客戶端的行數(shù)高說(shuō)明可能 SELECT *
Rows examine掃描的行數(shù)對(duì)比 Rows sent,比值越大效率越低
Rows affected變更的行數(shù)DML 語(yǔ)句的影響面
Tmp tables創(chuàng)建臨時(shí)表次數(shù)高說(shuō)明需要優(yōu)化 GROUP BY / ORDER BY
Tmp disk tbl磁盤臨時(shí)表次數(shù)高說(shuō)明內(nèi)存不足,性能急劇下降

排名部分關(guān)鍵字段

字段含義判斷標(biāo)準(zhǔn)
Response time該 SQL 總耗時(shí)及占比占比 > 10% 必須優(yōu)化
Calls執(zhí)行次數(shù)高頻慢查詢影響面更大
R/Call平均每次耗時(shí)> 1s 必須優(yōu)化,> 100ms 建議優(yōu)化
V/M響應(yīng)時(shí)間方差均值比> 0.1 說(shuō)明執(zhí)行時(shí)間波動(dòng)大,可能存在鎖競(jìng)爭(zhēng)

分析口訣:先看 Response time 占比找元兇 → 再看 Calls 確認(rèn)影響面 → 最后看 R/Call 評(píng)估單次傷害。

四、第三步:診斷執(zhí)行計(jì)劃

找到 TOP 慢 SQL 后,用 EXPLAIN 診斷其執(zhí)行計(jì)劃。

4.1 EXPLAIN 關(guān)鍵字段速查

上圖展示了 MySQL Workbench 的可視化執(zhí)行計(jì)劃,能直觀看到:

  • 全表掃描(Full Table Scan)的代價(jià)
  • 嵌套循環(huán)連接(Nested Loop Join)的過(guò)程
  • 索引查找(Key Lookup)的效率對(duì)比

核心字段診斷

字段正常值危險(xiǎn)值優(yōu)化方向
typeref/range/eq_refALL/index創(chuàng)建/調(diào)整索引
key有具體索引名NULL檢查 WHERE 條件是否命中索引
rows遠(yuǎn)小于表總行數(shù)接近表總行數(shù)增加過(guò)濾條件或優(yōu)化索引
ExtraUsing indexUsing filesort/Using temporary利用覆蓋索引、簡(jiǎn)化排序分組

4.2 常見執(zhí)行計(jì)劃問(wèn)題診斷

-- 案例:檢查一個(gè)慢查詢的執(zhí)行計(jì)劃
EXPLAIN ANALYZE
SELECT o.*, u.name 
FROM orders o 
JOIN user u ON o.user_id = u.id 
WHERE o.status = 'pending' 
  AND o.create_time > '2024-01-01'
ORDER BY o.create_time DESC 
LIMIT 100;

常見問(wèn)題排查

  1. type = ALL:全表掃描。檢查是否有合適索引、是否索引失效、是否數(shù)據(jù)量過(guò)大導(dǎo)致優(yōu)化器放棄索引。
  2. Extra = Using filesort:需要額外排序。嘗試將 ORDER BY 列加入索引,或利用覆蓋索引避免回表后排序。
  3. Extra = Using temporary:需要?jiǎng)?chuàng)建臨時(shí)表。常見于復(fù)雜 GROUP BY,嘗試簡(jiǎn)化查詢或調(diào)整 GROUP BY 順序匹配索引。
  4. rows 遠(yuǎn)大于實(shí)際返回?cái)?shù):說(shuō)明掃描了大量無(wú)效數(shù)據(jù)。檢查索引選擇性,或增加更精確的過(guò)濾條件。

五、第四步:優(yōu)化實(shí)戰(zhàn)

案例 1:SELECT * 導(dǎo)致的回表災(zāi)難

場(chǎng)景:訂單查詢頁(yè)面加載緩慢,用戶反饋卡頓。

-- 原始慢查詢 (平均 2.3s)
SELECT * FROM orders 
WHERE user_id = 12345 
  AND status = 'completed' 
ORDER BY create_time DESC 
LIMIT 10;

診斷

EXPLAIN SELECT * FROM orders WHERE user_id = 12345 AND status = 'completed' ...
-- 結(jié)果: type=ref, key=idx_user_id, rows=15000, Extra=Using where; Using filesort

問(wèn)題分析:

  • 索引 idx_user_id 只包含 user_id,過(guò)濾后仍有 15000 行
  • SELECT * 導(dǎo)致回表 15000 次
  • ORDER BY create_time 需要額外排序(filesort)

優(yōu)化方案

-- 創(chuàng)建覆蓋索引,包含 WHERE、ORDER BY、SELECT 需要的所有列
CREATE INDEX idx_user_status_time 
ON orders(user_id, status, create_time, order_no, amount, pay_time);

-- 改寫查詢,只取必要字段(利用覆蓋索引)
SELECT order_no, amount, status, create_time, pay_time 
FROM orders 
WHERE user_id = 12345 
  AND status = 'completed' 
ORDER BY create_time DESC 
LIMIT 10;

優(yōu)化后 EXPLAIN

type=ref, key=idx_user_status_time, rows=120, Extra=Using index

效果:查詢耗時(shí)從 2.3s → 12ms,提升 190 倍。

案例 2:深分頁(yè) LIMIT 100000, 10 的性能陷阱

場(chǎng)景:后臺(tái)管理系統(tǒng)翻頁(yè)到第 10000 頁(yè)后,頁(yè)面加載超過(guò) 5 秒。

-- 原始慢查詢 (平均 4.8s)
SELECT * FROM orders 
WHERE status = 'completed' 
ORDER BY create_time DESC 
LIMIT 100000, 10;

診斷

type=index, key=idx_status_time, rows=100010, Extra=Using where

問(wèn)題分析:MySQL 的 LIMIT 實(shí)現(xiàn)是「先掃描 100010 行,再丟棄前 100000 行」,越往后越慢。

優(yōu)化方案 1:延遲關(guān)聯(lián)(Deferred Join)

-- 先查主鍵,再回表取數(shù)據(jù)
SELECT o.* 
FROM orders o
JOIN (
    SELECT id 
    FROM orders 
    WHERE status = 'completed' 
    ORDER BY create_time DESC 
    LIMIT 100000, 10
) tmp ON o.id = tmp.id;

優(yōu)化方案 2:基于游標(biāo)的分頁(yè)(推薦)

-- 上一頁(yè)最后一條記錄的 create_time 為 '2024-03-15 14:30:00'
SELECT * FROM orders 
WHERE status = 'completed' 
  AND create_time < '2024-03-15 14:30:00'
ORDER BY create_time DESC 
LIMIT 10;

效果:方案 2 從 4.8s → 15ms,且性能不隨頁(yè)碼增加而下降。

案例 3:隱式類型轉(zhuǎn)換導(dǎo)致索引失效

場(chǎng)景:手機(jī)號(hào)查詢接口偶發(fā)卡頓,有時(shí) 50ms,有時(shí) 3s。

-- 表結(jié)構(gòu)
CREATE TABLE user (
    id INT PRIMARY KEY,
    phone VARCHAR(20),  -- 注意是 VARCHAR
    INDEX idx_phone (phone)
);

-- 原始查詢(Java 代碼傳入 long 類型)
SELECT * FROM user WHERE phone = 13800138000;

診斷

EXPLAIN SELECT * FROM user WHERE phone = 13800138000;
-- 結(jié)果: type=ALL, key=NULL, rows=5000000

問(wèn)題分析:phone 是 VARCHAR,傳入數(shù)字時(shí) MySQL 隱式將 phone 列轉(zhuǎn)換為數(shù)字再比較,相當(dāng)于對(duì)索引列做了函數(shù)處理,導(dǎo)致索引失效。

優(yōu)化方案

// 修改 Java 代碼,確保傳入字符串
String phone = "13800138000";  // 原來(lái)是 Long phone = 13800138000L;
jdbcTemplate.query("SELECT * FROM user WHERE phone = ?", phone);

效果:查詢耗時(shí)從 3s → 5ms

案例 4:OR 條件導(dǎo)致的全表掃描

場(chǎng)景:訂單搜索功能支持按訂單號(hào)或手機(jī)號(hào)查詢,慢查詢?nèi)罩局性?SQL 頻繁出現(xiàn)。

-- 原始慢查詢 (平均 1.5s)
SELECT * FROM orders 
WHERE order_no = 'ORD2024001' 
   OR user_phone = '13800138000';

診斷

type=ALL, key=NULL, rows=10000000

問(wèn)題分析:OR 兩邊條件分別適合不同索引(idx_order_noidx_user_phone),但優(yōu)化器選擇全表掃描。

優(yōu)化方案:拆分為 UNION ALL

-- 優(yōu)化后查詢 (平均 15ms)
SELECT * FROM orders WHERE order_no = 'ORD2024001'
UNION ALL
SELECT * FROM orders WHERE user_phone = '13800138000' 
  AND order_no <> 'ORD2024001';  -- 避免重復(fù)

效果:從 1.5s → 15ms,提升 100 倍。

案例 5:統(tǒng)計(jì)查詢的索引優(yōu)化與緩存策略

場(chǎng)景:首頁(yè) Dashboard 需要實(shí)時(shí)統(tǒng)計(jì)今日訂單金額和數(shù)量,每刷新一次就查一次數(shù)據(jù)庫(kù)。

-- 原始慢查詢 (平均 800ms,并發(fā)高時(shí)更慢)
SELECT 
    COUNT(*) AS order_count,
    SUM(amount) AS total_amount,
    AVG(amount) AS avg_amount
FROM orders 
WHERE create_time >= CURDATE();

診斷

type=range, key=idx_create_time, rows=50000, Extra=Using index condition

問(wèn)題分析:雖然走了索引,但掃描行數(shù)多,且是聚合計(jì)算,CPU 開銷大。高并發(fā)時(shí)成為瓶頸。

優(yōu)化方案 1:覆蓋索引

-- 創(chuàng)建覆蓋索引(只包含查詢需要的列)
CREATE INDEX idx_create_time_amount 
ON orders(create_time, amount);

-- 查詢變?yōu)楦采w索引掃描
SELECT COUNT(*), SUM(amount), AVG(amount)
FROM orders 
WHERE create_time >= CURDATE();

優(yōu)化方案 2:冗余統(tǒng)計(jì)表(最終采用)

-- 創(chuàng)建統(tǒng)計(jì)表
CREATE TABLE order_daily_stats (
    stat_date DATE PRIMARY KEY,
    order_count INT,
    total_amount DECIMAL(18,2),
    avg_amount DECIMAL(18,2),
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 通過(guò)定時(shí)任務(wù)或觸發(fā)器更新(每 5 分鐘)
INSERT INTO order_daily_stats (stat_date, order_count, total_amount, avg_amount)
SELECT CURDATE(), COUNT(*), SUM(amount), AVG(amount)
FROM orders 
WHERE create_time >= CURDATE()
ON DUPLICATE KEY UPDATE
    order_count = VALUES(order_count),
    total_amount = VALUES(total_amount),
    avg_amount = VALUES(avg_amount);

-- 查詢變?yōu)楹撩爰?jí)
SELECT * FROM order_daily_stats WHERE stat_date = CURDATE();

效果:從 800ms → 2ms,且不受并發(fā)影響。

六、第五步:驗(yàn)證優(yōu)化效果

優(yōu)化后必須驗(yàn)證,避免引入新問(wèn)題。

6.1 EXPLAIN 對(duì)比驗(yàn)證

-- 優(yōu)化前保存執(zhí)行計(jì)劃
EXPLAIN SELECT ... \G  -- 保存輸出

-- 優(yōu)化后對(duì)比
EXPLAIN SELECT ... \G  -- 確認(rèn) type、rows、Extra 改善

6.2 性能測(cè)試

# 使用 mysqlslap 壓測(cè)
mysqlslap --concurrency=50 --iterations=10 \
  --query="SELECT order_no, amount FROM orders WHERE user_id = 12345 AND status = 'completed' ORDER BY create_time DESC LIMIT 10" \
  --create-schema=mydb --delimiter=";" \
  --engine=innodb --number-of-queries=1000

# 或使用 sysbench
sysbench oltp_read_only --mysql-host=localhost --mysql-user=root \
  --mysql-password=xxx --mysql-db=mydb --tables=10 --table-size=1000000 \
  --threads=64 --time=60 --report-interval=10 run

6.3 生產(chǎn)灰度驗(yàn)證

-- 使用 MySQL 8.0 的 Query Rewrite 插件,先對(duì)部分流量生效
INSTALL PLUGIN query_rewrite SONAME 'rewriter.so';

-- 添加重寫規(guī)則(先對(duì) 10% 流量生效,驗(yàn)證無(wú)誤后再全量)
INSERT INTO query_rewrite.rewrite_rules (pattern, replacement, enabled)
VALUES (
    'SELECT * FROM orders WHERE user_id = ? AND status = ? ORDER BY create_time DESC LIMIT ?',
    'SELECT order_no, amount, status, create_time, pay_time FROM orders WHERE user_id = ? AND status = ? ORDER BY create_time DESC LIMIT ?',
    'YES'
);
CALL query_rewrite.flush_rewrite_rules();

七、第六步:搭建監(jiān)控體系

7.1 Prometheus + mysqld_exporter 監(jiān)控

# docker-compose.yml
version: '3'
services:
  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
  mysqld_exporter:
    image: prom/mysqld-exporter
    environment:
      - DATA_SOURCE_NAME=root:password@(mysql:3306)/
    ports:
      - "9104:9104"
  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"

關(guān)鍵監(jiān)控指標(biāo)

指標(biāo)PromQL告警閾值
慢查詢速率rate(mysql_global_status_slow_queries[5m])> 10/min
平均查詢耗時(shí)mysql_global_status_slow_queries / mysql_global_status_queries> 1%
全表掃描次數(shù)rate(mysql_global_status_select_scan[5m])> 100/min
活躍連接數(shù)mysql_global_status_threads_running> 80% max_connections
鎖等待時(shí)間mysql_global_status_innodb_row_lock_waits> 50/min

上圖展示了 Grafana 中 MySQL 監(jiān)控看板的典型布局,可以直觀看到:

  • 系統(tǒng)指標(biāo)(CPU、內(nèi)存、磁盤 IO)
  • MySQL 指標(biāo)(延遲、QPS、慢查詢數(shù)、活躍連接數(shù))
  • 異??蛻舳诉B接預(yù)警

7.2 慢查詢自動(dòng)巡檢腳本

#!/bin/bash
# slow_query_check.sh - 每日慢查詢巡檢
LOG_FILE="/var/log/mysql/slow.log"
REPORT_FILE="/tmp/slow_report_$(date +%Y%m%d).txt"
THRESHOLD=10  # 慢查詢數(shù)量閾值
# 生成報(bào)告
pt-query-digest --limit 20 $LOG_FILE > $REPORT_FILE
# 提取 TOP 1 的耗時(shí)占比
TOP_PCT=$(grep -A 1 "Rank Query ID" $REPORT_FILE | head -3 | tail -1 | awk '{print $3}')
# 發(fā)送告警
if [ $(echo "$TOP_PCT > $THRESHOLD" | bc) -eq 1 ]; then
    curl -X POST "https://oapi.dingtalk.com/robot/send?access_token=xxx" \
      -H "Content-Type: application/json" \
      -d "{"msgtype": "markdown", "markdown": {"title": "MySQL慢查詢告警", "text": "### MySQL 慢查詢告警\nTOP 1 慢查詢占比: ${TOP_PCT}%\n請(qǐng)查看報(bào)告: ${REPORT_FILE}"}}"
fi
# 歸檔日志(可選)
mv $LOG_FILE /var/log/mysql/slow_$(date +%Y%m%d).log
mysqladmin -uroot -p flush-logs slow

八、慢查詢優(yōu)化總結(jié):決策矩陣

問(wèn)題類型診斷特征優(yōu)化手段預(yù)期效果
全表掃描type=ALL, rows≈總行數(shù)創(chuàng)建索引、調(diào)整 WHERE 條件10~1000 倍提升
回表過(guò)多Extra=Using where, key 有值覆蓋索引、減少 SELECT 字段5~50 倍提升
文件排序Extra=Using filesort索引包含 ORDER BY 列、利用覆蓋索引3~20 倍提升
深分頁(yè)LIMIT 100000+, rows 巨大延遲關(guān)聯(lián)、游標(biāo)分頁(yè)、ES 替代100~1000 倍提升
隱式轉(zhuǎn)換key=NULL, 列類型與傳入值不匹配保持類型一致、代碼層面修復(fù)10~1000 倍提升
OR 失效type=ALL, 多個(gè) OR 條件UNION ALL 拆分、分別走索引10~100 倍提升
聚合統(tǒng)計(jì)大表 COUNT/SUM/AVG覆蓋索引、冗余統(tǒng)計(jì)表、緩存10~500 倍提升
鎖競(jìng)爭(zhēng)Lock time 高, V/M > 0.1減少事務(wù)范圍、調(diào)整隔離級(jí)別、優(yōu)化索引2~10 倍提升

九、面試高頻考點(diǎn)速記

Q1:如何定位生產(chǎn)環(huán)境的慢查詢?

  1. 開啟 slow_query_log 和 log_queries_not_using_indexes
  2. 使用 pt-query-digest 分析慢日志,按 Response time 排序找 TOP SQL
  3. 結(jié)合 Performance Schema 的 events_statements_summary_by_digest 查看實(shí)時(shí)數(shù)據(jù)
  4. 使用 sys 庫(kù)的 statements_with_full_table_scans 等視圖快速定位問(wèn)題

Q2:pt-query-digest 報(bào)告中的 V/M 是什么意思?

V/M 是響應(yīng)時(shí)間的方差均值比(Variance-to-Mean ratio)。值越大說(shuō)明 SQL 執(zhí)行時(shí)間波動(dòng)越大,可能存在鎖競(jìng)爭(zhēng)、數(shù)據(jù)分布不均或緩存命中率低的問(wèn)題。V/M > 0.1 需要關(guān)注。

Q3:LIMIT 100000, 10 為什么慢?如何優(yōu)化?

MySQL 的 LIMIT 實(shí)現(xiàn)是先掃描 offset + limit 行,再丟棄 offset 行。深分頁(yè)時(shí)掃描量巨大。
優(yōu)化方案:1)延遲關(guān)聯(lián)先查主鍵再回表;2)基于上一頁(yè)最后記錄的游標(biāo)分頁(yè)(推薦);3)使用搜索引擎(ES)替代。

Q4:SELECT * 為什么不好?

  1. 增加網(wǎng)絡(luò) IO,返回?zé)o用數(shù)據(jù);2. 無(wú)法使用覆蓋索引,必須回表;3. 增加內(nèi)存消耗;4. 表結(jié)構(gòu)變更可能導(dǎo)致應(yīng)用報(bào)錯(cuò)。應(yīng)只查詢需要的字段。

Q5:優(yōu)化后如何驗(yàn)證效果?

  1. EXPLAIN 對(duì)比執(zhí)行計(jì)劃(type、rows、Extra 改善);2. mysqlslap / sysbench 壓測(cè)對(duì)比 QPS/TPS;3. 生產(chǎn)灰度發(fā)布,觀察慢查詢?nèi)罩竞捅O(jiān)控指標(biāo);4. 關(guān)注業(yè)務(wù)指標(biāo)(頁(yè)面加載時(shí)間、接口成功率)。

結(jié)語(yǔ)

慢查詢優(yōu)化是一個(gè)系統(tǒng)工程:從日志配置到工具分析,從執(zhí)行計(jì)劃診斷到 SQL 改寫,從索引設(shè)計(jì)到架構(gòu)調(diào)整,最后通過(guò)監(jiān)控體系持續(xù)閉環(huán)。

記住三個(gè)核心原則:

  1. 先定位再優(yōu)化:用數(shù)據(jù)說(shuō)話,不要憑感覺改 SQL
  2. 索引是銀彈但不是萬(wàn)能:覆蓋索引能解決 80% 的查詢性能問(wèn)題,但深分頁(yè)、聚合統(tǒng)計(jì)需要架構(gòu)層面解決
  3. 監(jiān)控是閉環(huán)的關(guān)鍵:沒有監(jiān)控的優(yōu)化等于沒優(yōu)化,問(wèn)題會(huì)反復(fù)出現(xiàn)

上圖展示了真實(shí)的優(yōu)化效果對(duì)比:優(yōu)化前數(shù)據(jù)庫(kù)操作耗時(shí)波動(dòng)劇烈(峰值 6s+),優(yōu)化后趨于平穩(wěn)(<1s)。這正是慢查詢優(yōu)化帶來(lái)的直接業(yè)務(wù)價(jià)值。

以上就是MySQL慢查詢分析與優(yōu)化全過(guò)程的詳細(xì)內(nèi)容,更多關(guān)于MySQL慢查詢分析與優(yōu)化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Mysql更新varchar存儲(chǔ)Json數(shù)據(jù)的操作方法

    Mysql更新varchar存儲(chǔ)Json數(shù)據(jù)的操作方法

    這篇文章主要介紹了Mysql更新varchar存儲(chǔ)Json數(shù)據(jù)的操作方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-12-12
  • 簡(jiǎn)單談?wù)凪ySQL5.7 JSON格式檢索

    簡(jiǎn)單談?wù)凪ySQL5.7 JSON格式檢索

    MySQL 5.7.7 labs版本開始InnoDB存儲(chǔ)引擎已經(jīng)原生支持JSON格式,該格式不是簡(jiǎn)單的BLOB類似的替換。下面我們來(lái)詳細(xì)探討下吧
    2017-01-01
  • mysql實(shí)現(xiàn)將date字段默認(rèn)值設(shè)置為CURRENT_DATE

    mysql實(shí)現(xiàn)將date字段默認(rèn)值設(shè)置為CURRENT_DATE

    這篇文章主要介紹了mysql實(shí)現(xiàn)將date字段默認(rèn)值設(shè)置為CURRENT_DATE問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 如何添加一個(gè)mysql用戶并給予權(quán)限詳解

    如何添加一個(gè)mysql用戶并給予權(quán)限詳解

    在很多時(shí)候我們并不會(huì)直接利用mysql的root用戶進(jìn)行項(xiàng)目的開發(fā),一般我們都會(huì)創(chuàng)建一個(gè)具有部分權(quán)限的用戶,下面這篇文章主要給大家介紹了關(guān)于如何添加一個(gè)mysql用戶并給予權(quán)限的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • mysql-8.0.30壓縮包版安裝和配置MySQL環(huán)境過(guò)程

    mysql-8.0.30壓縮包版安裝和配置MySQL環(huán)境過(guò)程

    該文章介紹了如何在Windows系統(tǒng)中下載、安裝和配置MySQL數(shù)據(jù)庫(kù),包括下載地址、解壓文件、創(chuàng)建和配置my.ini文件、設(shè)置環(huán)境變量、初始化MySQL服務(wù)、啟動(dòng)服務(wù)以及修改root用戶密碼等步驟
    2025-01-01
  • MySQL系列之開篇 MySQL關(guān)系型數(shù)據(jù)庫(kù)基礎(chǔ)概念

    MySQL系列之開篇 MySQL關(guān)系型數(shù)據(jù)庫(kù)基礎(chǔ)概念

    數(shù)據(jù)庫(kù)是指長(zhǎng)期儲(chǔ)存在計(jì)算機(jī)中的有組織的、可共享的數(shù)據(jù)集合,數(shù)據(jù)具有三大基本特點(diǎn),永久存儲(chǔ),有組織,可共享,是數(shù)據(jù)庫(kù)系統(tǒng)的核心,本文給大家分享MySQL關(guān)系型數(shù)據(jù)庫(kù)基礎(chǔ)概念,需要的朋友參考下吧
    2021-07-07
  • MySQL的兩種分頁(yè)方式之Offset/Limit分頁(yè)和游標(biāo)分頁(yè)詳解

    MySQL的兩種分頁(yè)方式之Offset/Limit分頁(yè)和游標(biāo)分頁(yè)詳解

    這篇文章主要對(duì)比了MySQL的Offset/Limit分頁(yè)與游標(biāo)分頁(yè),指出前者簡(jiǎn)單但存在數(shù)據(jù)漂移和性能缺陷,后者通過(guò)游標(biāo)避免這些問(wèn)題且更高效,建議根據(jù)業(yè)務(wù)場(chǎng)景選擇分頁(yè)方式,深度分頁(yè)或動(dòng)態(tài)數(shù)據(jù)宜用游標(biāo)分頁(yè),而延遲聯(lián)結(jié)可優(yōu)化Offset/Limit性能,需要的朋友可以參考下
    2025-09-09
  • MySQL數(shù)據(jù)庫(kù)事務(wù)原理及應(yīng)用

    MySQL數(shù)據(jù)庫(kù)事務(wù)原理及應(yīng)用

    MySQL數(shù)據(jù)庫(kù)事務(wù)是指一組數(shù)據(jù)庫(kù)操作,要么全部執(zhí)行成功,要么全部回滾。事務(wù)可以確保數(shù)據(jù)的一致性和完整性,避免了多個(gè)用戶同時(shí)對(duì)同一數(shù)據(jù)進(jìn)行修改所帶來(lái)的問(wèn)題。MySQL通過(guò)事務(wù)日志記錄事務(wù)的操作,支持事務(wù)的回滾和提交等操作
    2023-04-04
  • Mysql邏輯架構(gòu)詳解

    Mysql邏輯架構(gòu)詳解

    今天小編就為大家分享一篇關(guān)于Mysql邏輯架構(gòu)詳解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • 一文深入解析Mysql的開窗函數(shù)(易懂版)

    一文深入解析Mysql的開窗函數(shù)(易懂版)

    在MySQL中窗口函數(shù)是一類非常強(qiáng)大的函數(shù),它們?cè)试S你在不改變表數(shù)據(jù)的情況下,對(duì)數(shù)據(jù)進(jìn)行復(fù)雜的分析和計(jì)算,這篇文章主要介紹了Mysql開窗函數(shù)的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-09-09

最新評(píng)論

故城县| 出国| 贵阳市| 广灵县| 浮山县| 阳高县| 东山县| 永仁县| 平舆县| 丰县| 靖江市| 绩溪县| 阜南县| 三河市| 台湾省| 辽宁省| 杭锦后旗| 怀集县| 仪陇县| 福鼎市| 稻城县| 芜湖市| 呼伦贝尔市| 祁连县| 灵川县| 汝阳县| 家居| 海宁市| 蛟河市| 徐汇区| 隆子县| 邮箱| 噶尔县| 孝昌县| 寻乌县| 桓仁| 宁蒗| 成都市| 平谷区| 鄄城县| 吐鲁番市|