mysqlnotlike优化(数据库实战MySQL查询优化器参数 preferorderingindex介绍)

mysqlnotlike优化(数据库实战MySQL查询优化器参数 preferorderingindex介绍)

adminqwq 2026-01-22 社会资讯 1 次浏览 0个评论

一、概念介绍

prefer_ordering_index 是 MySQL 8.0.21 版本引入的优化器开关参数,通过 optimizer_switch 系统变量控制,其核心作用在于调整优化器对"排序索引"的偏好程度,直接影响执行计划的选择逻辑。

数据库实战:MySQL查询优化器参数 prefer_ordering_index介绍

官网文档:https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-21.html

1. 为什么这个参数的设置如此重要?

优化器决策的核心矛盾:当查询语句包含 WHERE 过滤条件和 ORDER BY 时,优化器面临两难选择:

选择排序索引:使用能避免额外排序的索引(如 ORDER BY 字段的索引),但可能需要扫描大量不满足 WHERE 条件的数据

选择过滤索引:使用能高效过滤数据的索引(如 WHERE 字段的索引),但需要额外进行排序操作

系统默认:prefer_ordering_index=on(默认)会优先选择排序索引,在高过滤性查询中导致全表扫描,性能可能下降好几倍。

2. 底层机制介绍

MySQL 优化器通过成本模型计算执行计划公式:

数据库实战:MySQL查询优化器参数 prefer_ordering_index介绍

总成本 = 索引扫描成本 + 排序成本 + 回表成本

prefer_ordering_index 通过调整排序成本的权重影响决策:

开启 (on):排序成本权重 × 1.5 → 优化器更倾向避免排序关闭 (off):排序成本权重 × 0.5 → 优化器更倾向高效过滤

说明:当 WHERE 条件过滤性 > ORDER BY 排序性时(如 status='shipped' 过滤掉 80% 数据),关闭此参数能显著提升性能。

3. 与 EXPLAIN 的深度关联

使用 EXPLAIN FORMAT=JSON 可清晰看到参数影响:

EXPLAIN FORMAT=JSON SELECT * FROM orders WHERE status = 'shipped' ORDER BY create_time DESC LIMIT 10;

开启参数:possible_keys 显示 idx_create_time,Extra 显示 Using index condition; Using filesort

关闭参数:possible_keys 显示 idx_status,Extra 显示 Using where; Using index

诊断技巧:当 Extra 出现 Using filesort 且 rows 值远大于 filtered 时,很有可能是 prefer_ordering_index 未优化。

二、创建测试表与数据脚本

以下脚本创建包含 100 万行数据的测试表,模拟电商订单场景:

数据库实战:MySQL查询优化器参数 prefer_ordering_index介绍

-- 创建测试表CREATE TABLE orders ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, status VARCHAR(20) NOT NULL, create_time DATETIME NOT NULL, INDEX idx_status (status), INDEX idx_create_time (create_time)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- 正确插入100万行数据(使用6个UNION ALL,每个100行)INSERT INTO orders (user_id, status, create_time)SELECT FLOOR(RAND() * 100000) AS user_id, CASE WHEN RAND() > 0.8 THEN 'shipped' ELSE 'pending' END AS status, NOW() - INTERVAL FLOOR(RAND() * 365) DAY AS create_timeFROM (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10) t1, (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10) t2, (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10) t3, (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10) t4, (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10) t5, (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10) t6LIMIT 1000000;ANALYZE TABLE orders;数据库实战:MySQL查询优化器参数 prefer_ordering_index介绍

数据库实战:MySQL查询优化器参数 prefer_ordering_index介绍

测试脚本说明:

status 字段 80% 为 pending,20% 为 shipped(高过滤性场景)

create_time 覆盖 1 年时间范围(模拟真实业务)

数据量 100 万行(足够展示性能差异)

三、三个实战案例深度分析案例 1:电商订单分页查询(高过滤性场景)

问题:获取用户订单的倒序分页(第 1000 页,每页 100 条)

SELECT * FROM orders WHERE status = 'shipped' ORDER BY create_time DESC LIMIT 100 OFFSET 99900;

默认行为(prefer_ordering_index=on):

数据库实战:MySQL查询优化器参数 prefer_ordering_index介绍

性能:1.2 秒(扫描 19.9 万行)问题:优化器选择 idx_create_time 索引,但需扫描大量 status != 'shipped' 的数据

优化后(prefer_ordering_index=off):

SET SESSION optimizer_switch = 'prefer_ordering_index=off';SELECT * FROM orders WHERE status = 'shipped' ORDER BY create_time DESC LIMIT 100 OFFSET 99900;

优化执行计划:

数据库实战:MySQL查询优化器参数 prefer_ordering_index介绍

性能:0.12 秒(扫描 2 万行,减少 90% I/O)

关键改进:优化器选择 idx_status 索引过滤 20% 数据,再排序

案例 2:用户行为日志统计(GROUP BY 优化)

问题:统计最近 7 天各 IP 的登录次数

SELECT ip, COUNT(*) AS cnt FROM login_logs WHERE login_time > DATE_SUB(NOW(), INTERVAL 7 DAY)GROUP BY ip;

表结构:

CREATE TABLE login_logs ( id BIGINT PRIMARY KEY, ip VARCHAR(15), login_time DATETIME, INDEX idx_ip_time (ip, login_time), INDEX idx_time_ip (login_time, ip));

默认行为(prefer_ordering_index=on):

优化器选择 idx_time_ip(因 ORDER BY 未显式出现,但 GROUP BY 隐含排序)Extra 显示 Using index; Using filesort → 需额外排序

优化方案:

SET SESSION optimizer_switch = 'prefer_ordering_index=off';

优化后效果:

优化器选择 idx_ip_time 索引Extra 显示 Using index → 避免排序(因索引顺序匹配 GROUP BY)性能提升:查询时间从 2.8 秒 → 0.3 秒(8.7 倍提升)

案例 3:商品评论 TOP-N 查询(高排序性场景)

问题:获取评分最高的 20 条评论

SELECT * FROM product_comments WHERE product_id = 1001 ORDER BY score DESC LIMIT 20;

表结构:

CREATE TABLE product_comments ( comment_id BIGINT PRIMARY KEY, product_id BIGINT, score TINYINT, content TEXT, INDEX idx_product_score (product_id, score));

默认行为(prefer_ordering_index=on):

数据库实战:MySQL查询优化器参数 prefer_ordering_index介绍

问题:优化器选择主键索引,需扫描 100 万行后排序

优化方案:

SET SESSION optimizer_switch = 'prefer_ordering_index=off';

优化执行计划:

数据库实战:MySQL查询优化器参数 prefer_ordering_index介绍

性能:0.02 秒(扫描 10 行,避免全表扫描)

关键改进:利用 idx_product_score 覆盖索引,直接返回排序结果

四、最佳实践与总结

何时关闭 prefer_ordering_index?

场景特征

推荐设置

理由

WHERE 条件过滤性强

off

高效过滤 > 排序成本

分页深度大(OFFSET > 1000)

off

避免全表扫描

GROUP BY 需排序

off

利用索引顺序避免 filesort

ORDER BY 字段区分度低

off

排序成本占比高

何时保持默认(on)?

ORDER BY 字段区分度极高(如时间戳)

WHERE 条件过滤性弱(如 WHERE status IN ('all'))

查询返回结果集小(LIMIT 10)

性能验证标准-- 检查排序操作SHOW STATUS LIKE 'Handler_sort';-- 对比优化前/后SET @start = NOW();SELECT ...;SELECT TIMESTAMPDIFF(MICROSECOND, @start, NOW()) AS duration;

终极建议:在业务高峰期,对核心查询进行 prefer_ordering_index=off 优化,通常能获得 5-10 倍的性能提升,且无需修改表结构或索引。这是 MySQL 8.0 中被严重低估的查询优化技巧!

五、为什么这个参数如此冷门?

默认值陷阱:MySQL 默认开启,大部分开发者误以为这是最优配置。

优化器黑河:很多DBA通常只关注 EXPLAIN 的 type 和 key,忽略 optimizer_switch

场景特定性:仅在特定查询模式下有效(高过滤性 + ORDER BY)

行动建议:

下次遇到 ORDER BY 查询性能问题,先检查:

EXPLAIN 中是否出现 Using filesortWHERE 条件是否能高效过滤数据尝试 SET SESSION optimizer_switch = 'prefer_ordering_index=off' 验证。

转载请注明来自海坡下载,本文标题:《mysqlnotlike优化(数据库实战MySQL查询优化器参数 preferorderingindex介绍)》

每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,1人围观)参与讨论

还没有评论,来说两句吧...