MySQL日期查询预估行数差异疑问:为何结果差近一倍?
为什么两个逻辑看似等价的MySQL查询,EXPLAIN预估行数差近一倍?
首先咱们得戳破一个误区:这两个WHERE条件其实逻辑并不等价,这正是预估行数差异的核心原因。
让我们拆解两个条件的实际覆盖范围:
- 第一个查询的条件是让
start_datetime介于2019-08-28 00:00:00和2019-08-29 23:59:59,完整覆盖了48小时(整整两天)。 - 第二个查询的条件是让
start_datetime介于2019-08-28和2019-08-29。这里要注意MySQL的隐式类型转换规则:当DATE类型的值和DATETIME类型的列比较时,MySQL会自动把DATE值转换成DATETIME类型的YYYY-MM-DD 00:00:00。所以第二个条件的实际上限是2019-08-29 00:00:00,只覆盖了24小时左右(从28号0点到29号0点)。
再看EXPLAIN的预估行数逻辑:
MySQL查询优化器是基于索引的统计信息来估算范围查询的行数的。第一个查询覆盖的时间范围刚好是第二个的两倍,所以预估行数接近一倍完全符合逻辑。
你可以通过执行实际的COUNT查询验证这一点:
-- 第一个条件的实际行数 select count(*) from game_instance where start_datetime between STR_TO_DATE(CONCAT(DATE_SUB(CURDATE(), INTERVAL 2 DAY), ' ', '00:00:00'), '%Y-%m-%d %H:%i:%s') and STR_TO_DATE(CONCAT(DATE_SUB(CURDATE(), INTERVAL 1 DAY), ' ', '23:59:59'), '%Y-%m-%d %H:%i:%s'); -- 第二个条件的实际行数 select count(*) from game_instance where start_datetime between DATE_SUB(CURDATE(), INTERVAL 2 DAY) and DATE_SUB(CURDATE(), INTERVAL 1 DAY);
大概率会发现第一个查询的实际行数是第二个的两倍左右,和EXPLAIN的预估结果一致。
最后补充个小建议:如果想让第二个条件和第一个等价,需要把上限调整为包含当天最后一秒,比如写成DATE_ADD(DATE_SUB(CURDATE(), INTERVAL 1 DAY), INTERVAL 86399 SECOND),这样就能覆盖到目标日期的23:59:59了。
内容的提问来源于stack exchange,提问作者j4nd3r53n
相关产品推荐
相关产品推荐

