应避免直接用year()和month()函数筛选,因其导致索引失效;建议改用范围查询如created_at >= '2023-05-01' and created_at
用
YEAR()和MONTH()函数直接提取年月筛选MySQL 和 SQL Server 支持
YEAR()、MONTH()这类日期函数,适合快速按年份和月份切片。但要注意:它们会强制对created_at字段做函数计算,导致无法使用索引——如果表有千万级订单,全表扫描会明显变慢。实操建议:
- 仅在数据量小(WHERE YEAR(created_at) = 2023 AND MONTH(created_at) = 5
- 生产环境高频查询必须避免这种写法,改用范围查询(见下一条)
- PostgreSQL 不支持
YEAR(),得用EXTRACT(YEAR FROM created_at),语法不通用用日期范围查询替代函数,保障索引可用
真正能走索引的方式是把“2023 年 5 月”转换成两个确定的时间边界:
'2023-05-01'到'2023-06-01'(左闭右开)。只要created_at字段上有索引,就能高效定位。实操建议:
- 写成
WHERE created_at >= '2023-05-01' AND created_at- 别用
BETWEEN,它包含右边界,容易漏掉最后一秒的订单(比如'2023-05-31 23:59:59'之后的数据)- 如果字段是
DATETIME或TIMESTAMP类型,确保字符串格式带时间部分,否则 MySQL 可能隐式补零影响精度用
DATE_FORMAT()做年月字符串匹配(慎用)MySQL 提供
DATE_FORMAT(created_at, '%Y-%m'),能生成类似'2023-05'的字符串,再用= '2023-05'匹配。看起来简洁,但本质仍是函数操作,同样无法利用索引。实操建议:
- 只用于开发调试或报表导出等低频场景
- 如果硬要用,至少加个注释说明性能风险,避免被后续维护者误当标准写法
- 注意时区:如果数据库用的是 UTC 时间,而业务要求按本地时区(如东八区)归月,得先用
CONVERT_TZ()转换,否则五月第一天凌晨的数据可能被算进四月PostgreSQL 或 SQLite 用户怎么写
PostgreSQL 没有
YEAR(),得靠EXTRACT或TO_CHAR;SQLite 连原生日期函数都弱,得靠strftime()。语法差异大,但核心逻辑不变:优先选范围查询。实操建议:
索引是否生效,往往只差一个函数调用;而业务上“5 月”的定义,可能和数据库存储的时区、字段精度、甚至前端传参格式悄悄对不上。
- PostgreSQL:
WHERE created_at >= '2023-05-01' AND created_at (直接支持)- PostgreSQL(兼容旧版):
WHERE EXTRACT(YEAR FROM created_at) = 2023 AND EXTRACT(MONTH FROM created_at) = 5(不推荐)- SQLite:
WHERE strftime('%Y-%m', created_at) = '2023-05'(只能这么写,但记得建函数索引或用范围模拟)











