mysql中yearweek()默认以周日为周首,业务常用周一为起点,应显式使用yearweek(date_col, 1);date_format(date_col, '%y-%m')仅适合分组展示,过滤须用真实日期条件;函数分组会导致索引失效,高量级场景建议预计算week_id并建索引。

MySQL中用YEARWEEK()按周汇总时要注意周起始日
MySQL默认把周日当作一周的开始,但多数业务场景需要周一为起点。直接用YEARWEEK(date_col)可能让同一自然周的数据被拆到两个YEARWEEK()值里。
解决办法是显式指定模式参数:YEARWEEK(date_col, 1)表示以周一为周首(模式1),YEARWEEK(date_col, 0)才是默认周日开头。国内报表基本都该用模式1。
示例:统计2024年每周订单数
SELECT YEARWEEK(created_at, 1) AS week_id, COUNT(*) AS order_count FROM orders WHERE created_at >= '2024-01-01' GROUP BY week_id ORDER BY week_id;
-
week_id是类似202401这样的整数,不是日期,排序没问题但可读性差 - 如果要显示“2024-W01”这类格式,得用
STR_TO_DATE(CONCAT(YEAR(created_at), ' ', WEEK(created_at, 1)), '%Y %u')再格式化,但性能略降 - 注意
WEEK()和YEARWEEK()的模式参数必须一致,否则跨年周(如2023-12-31可能是2024年第1周)会错乱
用DATE_FORMAT()按月汇总更直观但有隐含陷阱
DATE_FORMAT(date_col, '%Y-%m')生成'2024-01'字符串,看着清爽,但它本质是字符串分组,不能直接用于日期计算或范围筛选。
比如想查“最近3个月”,不能写WHERE DATE_FORMAT(created_at, '%Y-%m') >= '2024-03'——这会漏掉2024-03-31之后的数据,因为字符串比较不等价于日期比较。
正确做法是先算出时间边界:
SELECT DATE_FORMAT(created_at, '%Y-%m') AS ym, SUM(amount) AS total FROM sales WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL 3 MONTH) GROUP BY ym ORDER BY ym;
- 分组用
DATE_FORMAT()没问题,但过滤条件必须用真实日期函数,不能依赖格式化结果 - 如果字段是
DATETIME类型,created_at >= '2024-03-01'比DATE_FORMAT() = '2024-03'快得多,索引能生效 -
'%Y-%m'在中文环境不会出乱码,但'%Y年%m月'会导致无法索引且排序错乱,别这么写
跨年周汇总时YEARWEEK()和WEEKOFYEAR()行为不同
遇到2023-12-31这种日期,不同函数返回结果可能不一致:WEEKOFYEAR('2023-12-31')固定返回52或53,而YEARWEEK('2023-12-31', 1)可能返回202401(即算作2024年第1周)。
这意味着:如果只按WEEKOFYEAR()分组,2023-12-31和2024-01-01会被归到同一周;但按YEARWEEK()分组,它们大概率分属不同年份的周——后者更符合ISO标准,也更贴近业务理解。
- 报表系统建议统一用
YEARWEEK(col, 1),避免跨年数据被错误合并 -
WEEKOFYEAR()没有模式参数,没法控制周起始日,灵活性差 - 如果下游要对接BI工具(如Tableau、Superset),确认它们对
YEARWEEK()的解析逻辑是否一致,有些工具会自行转换成本地周定义
性能敏感场景优先用日期范围而非函数分组
在千万级订单表上,GROUP BY YEARWEEK(created_at, 1)会让created_at索引失效,全表扫描不可避免。
真正高效的做法是预计算分区字段:在表里加一列week_id INT,插入时用YEARWEEK(NOW(), 1)写入,然后对该列建索引并直接GROUP BY week_id。
- 实时性要求不高的话,也可以用物化视图(MySQL 8.0+支持)或定时任务汇总到宽表
- 临时查一次?加
FORCE INDEX(created_at)没用,函数包裹字段天然无法走索引 - 如果必须用函数,至少确保
WHERE子句里的日期条件能命中索引,把数据量先压下来再分组
YEARWEEK()的模式参数、DATE_FORMAT()的用途边界、还有索引能不能用——这三件事不搞清,统计结果可能对得上,但要么慢得没法忍,要么某几天的数据就悄悄偏移了。











