MySQL中慢查詢優(yōu)化的技術(shù)指南
1、簡(jiǎn)述
在 Java 后端開發(fā)中,數(shù)據(jù)庫(kù)是系統(tǒng)性能瓶頸的高發(fā)地帶,而 慢 SQL 查詢 往往是系統(tǒng)響應(yīng)遲緩的“罪魁禍?zhǔn)?rdquo;。本文將全面梳理慢 SQL 的優(yōu)化思路,并結(jié)合 Java 示例進(jìn)行實(shí)戰(zhàn)演練。
2、慢查詢的常見表現(xiàn)
慢查詢通常表現(xiàn)為:
- 接口響應(yīng)時(shí)間緩慢
- 數(shù)據(jù)庫(kù) CPU 占用高
- 表鎖、死鎖頻繁
- Java 應(yīng)用線程池阻塞嚴(yán)重
慢 SQL 的主要成因
| 成因類型 | 說明 |
|---|---|
| 未使用索引 | 全表掃描,查詢耗時(shí) |
| 使用了低效的函數(shù)或表達(dá)式 | 如 LIKE '%xx%', DATE() |
| 多表關(guān)聯(lián)不當(dāng) | join 條件缺失或不走索引 |
| 過多返回字段 | 只用到了部分字段卻 SELECT * |
| where 條件不精準(zhǔn) | 無(wú)法過濾大量無(wú)關(guān)數(shù)據(jù) |
| 數(shù)據(jù)庫(kù)設(shè)計(jì)不合理 | 字段冗余、缺乏范式、字段類型錯(cuò)誤等 |
3、慢查詢優(yōu)化的通用思路
加索引(重點(diǎn))
為 WHERE、JOIN、ORDER BY、GROUP BY 中涉及的字段加索引
避免使用函數(shù)包裹字段,如 LEFT(name, 3),會(huì)導(dǎo)致無(wú)法使用索引
使用 EXPLAIN 分析執(zhí)行計(jì)劃
EXPLAIN SELECT * FROM orders WHERE user_id = 100;
關(guān)注字段:
| 字段 | 說明 |
|---|---|
| type | 連接類型(越接近 const 越好) |
| rows | 掃描行數(shù)(越小越好) |
| key | 使用的索引名稱 |
| Extra | 是否使用臨時(shí)表、排序等 |
分頁(yè)優(yōu)化
避免深度分頁(yè):
-- 慢查詢(跳過大量行) SELECT * FROM orders LIMIT 1000000, 20; -- 推薦(使用上次主鍵記錄) SELECT * FROM orders WHERE id > 1000000 LIMIT 20;
拆表分區(qū)
垂直拆分:將大表按字段拆分為多個(gè)表
水平分表:按業(yè)務(wù)字段分庫(kù)分表(如 user_id 分表)
分區(qū)表:MySQL 原生支持(適合歷史歸檔數(shù)據(jù))
減少嵌套子查詢
使用 JOIN 或臨時(shí)表替代子查詢,更高效。
SQL 只查需要的字段
-- 慎用 SELECT * FROM user; -- 推薦 SELECT id, name, email FROM user;
4、慢 SQL 實(shí)踐排查與優(yōu)化
示例:慢查詢前后對(duì)比
原始 SQL(慢)
SELECT * FROM orders WHERE DATE(create_time) = '2024-01-01';
問題:
- 使用了 DATE() 函數(shù),索引失效
- 全表掃描,耗時(shí)嚴(yán)重
優(yōu)化 SQL(快)
SELECT * FROM orders WHERE create_time >= '2024-01-01 00:00:00' AND create_time < '2024-01-02 00:00:00';
優(yōu)點(diǎn):
- 范圍查詢走索引
- 支持時(shí)間范圍過濾
Java 中日志配置監(jiān)控慢 SQL
# application.yml 示例(Spring Boot)
logging:
level:
com.zaxxer.hikari.HikariConfig: DEBUG
com.zaxxer.hikari: TRACE
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo
username: root
password: root
hikari:
maximum-pool-size: 10
connection-timeout: 3000
使用工具(如 p6spy)打印 SQL 及耗時(shí),或開啟 MySQL 慢查詢?nèi)罩荆?/p>
-- MySQL 開啟慢查詢?nèi)罩? SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; -- 超過 1 秒記錄
SQL 優(yōu)化 checklist
- 是否使用了合適的索引
- 是否避免了函數(shù)、表達(dá)式阻礙索引
- 是否使用了 EXPLAIN 檢查執(zhí)行計(jì)劃
- 是否合理分頁(yè)、避免深度翻頁(yè)
- 是否控制了查詢字段數(shù)量
- 是否考慮拆分大表或分區(qū)表
- 是否避免了嵌套子查詢
5、SQL 優(yōu)化實(shí)戰(zhàn)樣例
場(chǎng)景 1:模糊查詢優(yōu)化
-- 慢:前置通配符無(wú)法使用索引 SELECT * FROM user WHERE name LIKE '%abc%'; -- 優(yōu)化:使用全文索引或右模糊匹配 SELECT * FROM user WHERE name LIKE 'abc%';
場(chǎng)景 2:避免函數(shù)阻礙索引
-- 慢 SELECT * FROM orders WHERE YEAR(create_time) = 2024; -- 快 SELECT * FROM orders WHERE create_time >= '2024-01-01' AND create_time < '2025-01-01';
場(chǎng)景 3:多字段組合索引使用順序
-- 有聯(lián)合索引 (user_id, status) -- 推薦:user_id 和 status 都參與 SELECT * FROM orders WHERE user_id = 100 AND status = 'PAID'; -- 不推薦:只用 status,索引無(wú)法生效 SELECT * FROM orders WHERE status = 'PAID';
6、結(jié)語(yǔ)
慢查詢是系統(tǒng)性能優(yōu)化的重要戰(zhàn)場(chǎng)。對(duì)于 Java 開發(fā)者而言,理解 SQL 執(zhí)行機(jī)制和優(yōu)化原則,比“用緩存”更根本、更有效。
日常開發(fā)中,應(yīng)做到:
- 編寫 SQL 前先考慮是否能走索引
- 查詢慢時(shí)第一時(shí)間用 EXPLAIN 排查
- 數(shù)據(jù)庫(kù)設(shè)計(jì)時(shí)就考慮查詢結(jié)構(gòu)
到此這篇關(guān)于MySQL中慢查詢優(yōu)化的技術(shù)指南的文章就介紹到這了,更多相關(guān)MySQL慢查詢內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL的查詢緩存機(jī)制基本學(xué)習(xí)教程
這篇文章主要介紹了MySQL的查詢緩存機(jī)制基本學(xué)習(xí)教程,默認(rèn)針對(duì)InnoDB存儲(chǔ)引擎下來(lái)將,需要的朋友可以參考下2015-11-11
mysql備份恢復(fù)mysqldump.exe幾個(gè)常用用例
收集了,一個(gè)整理不錯(cuò)的,mysql備份與恢復(fù)用法2008-08-08
一次MySQL啟動(dòng)導(dǎo)致的事故實(shí)戰(zhàn)記錄
這篇文章主要給大家介紹了一次MySQL啟動(dòng)導(dǎo)致的事故實(shí)戰(zhàn)記錄,記錄了MySQL 啟動(dòng)成功但未監(jiān)聽端口的解決方法,文中給出了詳細(xì)的解決方法,需要的朋友可以參考下2021-09-09
解決MySQL因不能創(chuàng)建 PID 導(dǎo)致無(wú)法啟動(dòng)的方法
這篇文章主要給大家介紹了關(guān)于解決MySQL因不能創(chuàng)建 PID 導(dǎo)致無(wú)法啟動(dòng)的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編一起來(lái)學(xué)習(xí)學(xué)習(xí)吧。2017-06-06
mysql入門之1小時(shí)學(xué)會(huì)MySQL基礎(chǔ)
今天剛好看到了SYZ01的這篇mysql入門文章,感覺對(duì)于想學(xué)習(xí)mysql的朋友是個(gè)不錯(cuò)的資料,腳本之家特分享一下,需要的朋友可以參考下2018-01-01

