MySQL 日期范围筛选为什么不走索引:半开区间、函数包裹与 EXPLAIN 核对
订单后台最常见的按日期筛选功能,上线后经常莫名其妙变成慢查询高发点:用户选了2026-07-01到2026-07-07的区间,SQL给order_created_at明明建了索引,MySQL还是扫了大半张表。先别急着删了索引重建,最容易踩的两个坑,要么是给时间列套了DATE()做运算,要么是偷懒把结束日的时间直接写成含糊的23:59:59。
明明建了对应索引的日期范围查询没走索引,大部分情况都不是索引本身出问题,要么是边界写法不符合索引的有序匹配规则,要么是你提前用运算破坏了索引列的原始值,调整写法再核对执行计划就能快速定位问题。
- 对已经建好索引的
DATETIME列,优先用「包含开始、不包含结束」的半开区间写法。 DATE(order_created_at)会破坏索引列的有序性,让过滤条件没法直接利用B+Tree的有序范围快速扫描。EXPLAIN重点看key、type、rows和Extra,别光盯着有没有建索引判断走不走索引。- 结束日期要先转成下一天的零点,避免漏掉当天带微秒精度的订单记录。
先把订单筛选的时间边界说清楚
假设表结构里有一列order_created_at DATETIME(6) NOT NULL,对应的索引名叫idx_orders_created_at。前端传过来的是两个用户选中的自然日,我们需要在程序里把它们转换成数据库能直接识别的精确时间点:
-- 2026-07-01 00:00:00 = '2026-07-01 00:00:00'
AND order_created_at
这个写法能把7月1日的所有记录都纳入筛选范围,也能把7月7日23:59:59.999999的订单也完整覆盖到。下次你再从7月8日零点开始筛选,两段区间的边界完全不会重叠,不会出现同一条记录被两个相邻日期同时统计到的问题。
为什么DATE()会让范围筛选变慢
不少列表接口开发图省事,会直接写出下面这类SQL:
WHERE DATE(order_created_at) BETWEEN '2026-07-01' AND '2026-07-07'
这种写法下MySQL需要先逐行对全表的记录计算DATE(order_created_at),再判断计算后的结果有没有落在你指定的区间里。哪怕order_created_at已经建了普通索引,条件也不是直接作用在原始的索引列上做连续范围比较。数据量小的时候你根本感知不到差别,等订单量涨上去之后,接口延迟会跟着扫描的行数一起往上涨,最终拖垮整个服务。

更稳妥的做法是在应用层先把前后两个日期转换成精确的起止时间,把原始时间列直接放在比较符号的左侧。数据库不需要逐行修改列值做运算,优化器可以直接顺着时间索引找对应的连续范围,性能会好很多。
三种写法放在同一张EXPLAIN里核对
为了直观对比不同写法的差别,你可以提前准备一张测试表,用完全相同的日期条件分别跑。别光靠经验判断索引走没走,一定要拉出来执行计划看实际效果:
EXPLAIN
SELECT id, user_id, total_amount
FROM orders
WHERE order_created_at >= '2026-07-01 00:00:00'
AND order_created_at
看执行计划的时候重点关注四个字段就行:
key:实际被优化器选中的索引,不能只看possible_keys里列出来的可选索引。type:范围查询正常情况下常见值是range,如果退化成了ALL,就要接着往下排查原因。rows:优化器预估需要检查的行数,这个数和最终返回的结果行数不是同一个概念。Extra:出现Using where并不直接代表异常;如果排序过程还触发了额外的临时表或者文件排序,要结合排序列和索引的顺序一起判断。
BETWEEN也能表达范围,但它是两端都包含的闭区间:
WHERE order_created_at BETWEEN '2026-07-01 00:00:00'
AND '2026-07-07 23:59:59'
如果你的时间列支持微秒精度,这种写法就会漏掉23:59:59之后、当天结束之前的所有记录。把结束时间转成下一天零点,再用小于号做判断,边界规则不管是写代码还是做测试都更容易统一,不容易出漏子。

列表接口还要处理排序和空值边界
日期条件改对之后,订单列表接口还是慢,问题大概率会转移到排序环节。如果接口固定要按最新生成的订单倒序展示,你可以先确认下查询是不是真的需要返回全部字段;比如订单详情里的大段JSON文本,完全没必要在列表查询阶段就读出来拖慢速度。
SELECT id, user_id, status, total_amount, order_created_at
FROM orders
WHERE order_created_at >= ?
AND order_created_at
加上id DESC是为了让同一时间戳下生成的订单也能有稳定的排序顺序。如果业务允许order_created_at为空,就要先明确空值的记录要不要出现在日期筛选的结果里;别为了兼容旧数据随手加OR order_created_at IS NULL,这会改变范围条件的选择性,要单独核对执行计划确认性能没有问题。
上线前用结果边界做一次复查
提前在测试库造四条边界测试数据:开始时刻、结束前一微秒、下一天零点,再加一条更早的历史订单。筛选7月1日到7月7日的区间时,前两条边界数据应该命中,下一天零点的记录和更早的历史订单都不应该出现在结果里。
-- 应该命中:2026-07-01 00:00:00
-- 应该命中:2026-07-07 23:59:59.999999
-- 不应命中:2026-07-08 00:00:00
-- 不应命中:2026-06-30 23:59:59.999999
再把实际业务参数放回接口跑一遍,记录一次EXPLAIN ANALYZE的耗时和实际扫描行数。随着表里数据分布变化,MySQL的索引选择可能会跟着变;更稳妥的做法是把这条查询加入慢查询日志长期观察,不要把某次测出来的执行计划当成永远生效的结论。
常见问题
日期列必须改成DATE类型吗?
完全没必要。订单场景大多需要保留时分秒的精度,直接继续用DATETIME或者其他合适的时间类型就好,只要用半开区间来筛选自然日,效果完全没问题。
明明有索引执行计划却显示type=ALL?
常见原因包括列被函数包裹、过滤范围的选择性太差、存在隐式类型转换,或者优化器判断直接全表扫描的成本比走索引更低。先核对实际执行的SQL、传入的参数类型和key,再用测试数据重新复查一遍就能定位问题。
结束日期能不能直接写当天23:59:59?
不建议把它当成通用规则。如果时间列支持微秒精度就会出现漏数据的情况,而且结束日的时间还可能受用户时区偏移的影响。转换成下一天零点再用小于号判断要稳得多。
索引里只放order_created_at就够了吗?
要看你固定的过滤条件、排序规则和表里的数据分布。先用真实业务SQL配合执行计划确认性能瓶颈,再决定要不要建联合索引,别为了一个列表页面堆上一堆不好维护的冗余索引。
总结:让数据库直接比较原始时间列
日期筛选优化的第一步绝对不是上来就重建索引,而是先把用户选中的自然日转换成明确的时间边界。去掉DATE()对原始列的包裹逻辑,采用「开始小于等于、结束小于」的半开区间写法,再用EXPLAIN核对实际选中的索引、扫描行数和排序的额外开销。这样既能减少统计漏数的问题,也能让订单列表的响应时间有明确的优化效果。
Go httptrace 怎么定位 HTTP 请求慢:DNS、连接复用与 TLS 分段证据
- 上一篇
- Go httptrace 怎么定位 HTTP 请求慢:DNS、连接复用与 TLS 分段证据
- 下一篇
- MySQL 8.0 直方图统计何时能救回错误执行计划:从基线到验证
-
- 数据库 · MySQL | 6小时前 |
- MySQL ST_AsGeoJSON 怎样控制几何输出的小数位
- 430浏览 收藏
-
- 数据库 · MySQL | 6小时前 |
- MySQL ST_IsClosed 怎样判断折线是否闭合
- 289浏览 收藏
-
- 数据库 · MySQL | 6小时前 |
- MySQL ST_GeometryN 怎样读取集合中的指定几何对象
- 264浏览 收藏
-
- 数据库 · MySQL | 6小时前 |
- MySQL ST_NumInteriorRing 怎样统计多边形内部孔洞
- 279浏览 收藏
-
- 数据库 · MySQL | 6小时前 |
- MySQL ST_ExteriorRing 怎样提取多边形外环
- 330浏览 收藏
-
- 数据库 · MySQL | 6小时前 |
- MySQL ST_Longitude 怎样读取地理点的经度
- 198浏览 收藏
-
- 数据库 · MySQL | 6小时前 |
- MySQL ST_SwapXY 怎样交换几何对象的坐标分量
- 381浏览 收藏
-
- 数据库 · MySQL | 6小时前 |
- MySQL ST_HausdorffDistance 怎样衡量两个几何集合的最大偏离
- 296浏览 收藏
-
- 数据库 · MySQL | 6小时前 | MySQL · mysql ST_FrechetDistance 空间函数 轨迹比较 LineString
- MySQL ST_FrechetDistance 怎样比较两条轨迹的形状差异
- 488浏览 收藏
-
- 数据库 · MySQL | 6小时前 |
- MySQL ST_LineInterpolatePoint 怎样定位折线上的比例位置
- 399浏览 收藏
-
- 数据库 · MySQL | 6小时前 | MySQL · 数据校验 · 空间数据 MySQL ST_Validate 几何有效性 WKT ST_IsValid
- MySQL ST_Validate 怎样检查并返回有效几何对象
- 387浏览 收藏
-
- 数据库 · MySQL | 6小时前 |
- MySQL ST_Simplify 怎样减少折线中的冗余点
- 384浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 734次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 736次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 815次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 776次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 611次使用
-
- MySQL 明明加了索引,为什么查询还是很慢?先查这 6 个点
- 2026-06-27 374浏览
-
- golang MySQL实现对数据库表存储获取操作示例
- 2022-12-22 499浏览
-
- golang 基于 mysql 简单实现分布式读写锁
- 2023-01-07 384浏览
-
- 详解如何利用GORM实现MySQL事务
- 2023-01-07 184浏览
-
- Go语言实现操作MySQL的基础知识总结
- 2023-01-23 265浏览

