96SEO 2026-08-06 21:17 1
业务背景订单列表查询,显示使用者的所有订单。
使用者痛点:面对数百万条订单记录。页面响应慢、等待时间长,导致使用者体验差、转化率下降。

-- 查询使用者订单列表
SELECT * FROM orders
WHERE user_id = AND status IN
AND create_time>= '--'
ORDER BY create_time DESC
LIMIT;
问题表现
EXPLAIN SELECT * FROM orders
WHERE user_id = AND status IN
AND create_time>= '--'
ORDER BY create_time DESC
LIMIT;
结果:
+----+-------------+--------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+------+---------+-------------+
| | SIMPLE | orders | ALL | NULL | NULL | NULL | NULL | | Using where |
+----+-------------+--------+------+---------------+------+---------+------+---------+-------------+
关键信息:
type = ALL: 全表扫描key = NULL: 没有使用索引rows = : 扫描了整张表!
SHOW INDEX FROM orders;
+-------+------------+----------+--------------+-------------+
| Table| Non_unique | Key_name| Seq_in_index| Column_name |
|------ +------------ +---------- +-------------- +-------------+
| orders| 0 || PRIMARY|| || id |
|------ +------------ +---------- +-------------- +-------------+
| orders| 0 || PRIMARY|| || id |
+
发现问题: 只有主键索引,没有针对查询字段的任何索引!老实说,这就是性能瓶颈所在。
再看调整方法一,添加复合索引
为什么要用这个顺序?
-- 添加复合索引
CREATE INDEX idx_user_status_time ON orders;
-
idx_user_status_time:
从查询条件来看,WHERE user_id = ✓ 最左前缀匹配
AND status IN ✓ 可以匹配
AND create_time>= '--' ✓ 可以匹配
ORDER BY create_time DESC ✓ 利用索引排序可以使用的查询:
✅ WHERE user_id =
✅ WHERE user_id = AND status =
✅ WHERE user_id = AND status IN
✅ WHERE user_id = AND create_time>= '--'
不可以使用的查询:
✗ WHERE status =
✗ WHERE create_time>= '--'
}
/**
*/
bash
EXPLAIN
EXPLAIN SELECT * FROM orders
WHERE user_id = AND status IN
AND create_time>= '--'
ORDER BY create_time DESC
LIMIT;
<代码类= hljs language= sql> +
diff
id select_type table type possible_keys key key_len ref rows Extra
-1- SIMPLE -orders range idx_user_status_
**说明**
-
type=range范围查询,比 ALL 好多。
-
key=idxuserstatus_time使用了新建的索引。话说回来,
-
rows :只扫描约1500 行。远低于5 百万,
-
执行时间 :从5.2 秒降到 0.03 秒提高 173 倍!
四、进一步调整
问题一的观点是,SELECT * 查询所有字段
sql
-- ❌ 不好:查询所有字段
SELECT * FROM orders WHERE user_id =;
-- ✅ 好:只查询需要的字段
SELECT id,orderno。amount,status,createtime
FROM orders
WHERE user_id =;
从问题二来看。深度分页导致大量扫描
sql
-- 问题:LIMIT offset 大量扫描
SELECT * FROM orders
WHERE userid =
ORDER BY createtime DESC LIMIT offset,page_size;
-- 方案一:子查询取最近 ID 再做分页
SELECT *
FROM (
SELECT id FROM orders
WHERE userid=... ORDER BY createtime DESC LIMIT offset。page_size) AS t1,orders t2
WHERE t1.id=t2.id;
-- 或者直接记住上一次最大 ID:
SELECT * FROM orders
WHERE userid=... AND id> lastmaxid
ORDER BY createtime DESC LIMIT pagesize;
至于问题三。覆盖索引
如果查询字段都在同一个索引里就不需要回表:
sql
-- 当前仅有 idxuserstatus_time
-- 查询字段包含 id 等非列入该索引的数据,导致回表。
-- 调整:
CREATE INDEX idxuserstatuscover ON orders(
userid。status,createtime,id,orderno,amount);
EXPLAIN SELECT id,id... FROM ...;-- Extra 显示 Using index 表示无回表。
五、实际案例调整
调整项
调整前
调整后
效果更好
全表扫描
500 万行
无索引
范围扫描
1500 行
使用 idx_user_status_cover
≈173 倍速
六、EXPLAIN 字段详解
字段名
说明
好的值
差的值
id
表示该条记录在整个 JOIN 中的位置,也是内部递增编号。可用来判断同一条语句中多次出现的相同子句。也能判断主键是否重复,
唯一递增值,从小到大;如单独出现则为 1,多次出现则按顺序递增。
重复或不规范编号会影响 JOIN 的实现效率。
selecttype
单独 SELECT 为 SIMPLE;子查询为 SUBQUERY;UNION 为 UNION;老实说,UNION DISTINCT 为 UNION DISTINCT 等。
SIMPLE 是最简单也是最快的类型。话说回来,
SUBQUERY 与 UNION 往往代表着额外复制成本和更低效率。
type
访问类型,用来衡量访问方式好坏。越靠左越好,常见顺序如下所示。
;const>>>>> → eqref → ref → range → index → ALL
-->
possiblekeys / key / keylen -->
七、常见慢查询场景及对应解决思路
场景一这方面。函数导致失效—— 索引失效,可
为范围过滤器。
sql
-- ❌ 索引失效:
SELECT * FROM orders WHERE DATE ='2026‑08‑06';
-- ✅ 使用范围条件让 MySQL 能利用创建时间列上的 B‑Tree 索引:
SELECT * FROM orders
WHERE create_time BETWEEN '2026‑08‑06 00 00 00' AND '2026‑08‑06 23 59 59';
再看场景二,LIKE 模糊匹配 – 前置 % 时无法利用 B‑Tree 索引。改为后置 % 或全文检索.
sql
-- ❌ 无法利用 MySQL 的 B‐Tree:
SELECT * FROM orders WHERE order_no LIKE '%12345';
从场景三来看,OR 条件 – 把 OR 拆成两条 UNION ALL 并分别建立对应单列或组合列的索引用来提高性能.
sql
-- ❌ OR 损耗大:
SELECT * FROM orders WHERE user_id=?OR status=,;
-- ✅ 用 UNION ALL 分拆:
UNION ALL
场景四这方面。"NOT",",=","<>" 等不等式 – MySQL 通常会退回全表扫描。需要
为大于、小于等可利用范围筛选符号.
sql
SELECT * from users where age <>?,
八、慢查询监控与排查工具
开启慢日志(MySQL)
bash
SHOW VARIABLES LIKE 'slowquery%';SHOW VARIABLES LIKE 'longquery_time';
SET GLOBAL slowquerylog ='ON';SET GLOBAL longquerylogfile='/var/log/mysql/slow.log';不过,SET GLOBAL longquerylogformat ='FORMAT';# 如果想看完整 SQL 可选 json/text;SET GLOBAL longquerylogbasename='/var/log/mysql';怎么说呢,SET GLOBAL longquerylogrotationage=%d;SET GLOBAL longquerylogrotationsize=%d;SET GLOBAL longquerylogrotateoncreate=%s;
SET GLOBAL slowquerylogfile='/tmp/mysqlslow.log';其实,SET GLOBAL longqueryinterval=%d;SET GLOBAL log_output='%s';
SHOW VARIABLES LIKE 'slow*';SHOW VARIABLES LIKE 'log%';SHOW VARIABLES LIKE 'log_%';SHOW VARIABLES LIKE '%long%';SHOW VARIABLES LIKE '%query%';
SHOW VARIABLES LIKE 'slowquerylog_file';
从分析日志工具来看,
-
mysqldumpslow - 对日志进行聚合分析
-
pt-query-digest - Percona Toolkit 强力工具,可生成详细报告
例子的观点是。
bash
tail -n200 -f /var/log/mysql/slow.log
mysqldumpslow -s t -t /var/log/mysql/slow.log
pt-query-digest /var/log/mysql/slow.log --output=json --sort=time>> report.json
九、与互动
# 要点 #:
- 快速定位慢查询,用 EXPLAIN 明确 type/key/rows 三个维度。
-
建立符合业务逻辑且满足“最左前缀”原则的复合索引。
-
覆盖 Index,让回表消失。
-
避免函数、LIKE 前置%、OR、不等式导致失效。
-
对深度分页采用记住上一次最大 ID 或子查询分块。
-
开启慢日志,并结合 mysqldumpslow/PT 等工具做持续监控。
— 每一步都能直接带来数十倍甚至百倍性能提高。
请把你自己的案例分享出来一起探讨如何把理论落地吧!🎯🛠️
💬 今日互动
你项目里遇到过哪些“看似正常却极其慢”的 SQL?你是怎么发现并解决它们的?欢迎留言讨论,
。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback