MySQL时间范围比较:实例与解析

过去一周订单用 DATE_SUB(NOW(), INTERVAL 1 WEEK)。

查 2 02 3 年数据用 WHERE order_time BETWEEN '2 02 3 -01 -01 ' AND '2 02 3 -1 2 -3 1 '。

索引要加在 order_time 上,比如 CREATE INDEX idx_order_time ON orders(order_time)。

自己掂量。

mysql 数据库中索引原理分析说明

哎,这MySQL的索引啊,真的是让我这个搞数据库的头疼不已。
记得有一次,我在一个项目里,为了提高查询效率,直接在主键上建立了一个超级大的非聚集索引,结果呢?服务器差点就瘫痪了。
那是一个什么场景呢?2 01 9 年,我们在一个电商平台上,为了优化订单查询,给订单ID这个字段建立了一个非聚集索引。

我当时就想,主键不就应该用聚集索引吗?结果一查资料,才发现主键不一定就是聚集索引。
有时候,你用聚集索引,可能就是在给自己挖坑。
就像我那次,订单数据量庞大,查询频繁,结果这个聚集索引一建立,CPU和内存压力都大了。

后来,我改用了非聚集索引,结果订单查询速度确实上去了,但是更新操作就慢了。
哎,这就是所谓的权衡吧。
不过说回来,这玩意儿得根据具体情况来定。
比如说,那个日期字段,我之前一直觉得应该用非聚集索引,后来一测试,发现建立聚集索引后查询速度提升了5 0%,这让我对索引的理解又深了一层。

总之,这索引啊,得像养孩子一样,得看情况。
有时候你给它吃饱了,它长得快,有时候你得饿它一顿,让它休息休息。
所以啊,搞数据库的,一定要多实践,多总结,别光看理论,要像我现在这样,踩过坑才能长记性。
哈哈,跟你说这些,就是想让你也少走点弯路。

MySQL时间格式化函数解析 where查询中日期范围筛选技巧

好家伙,这简直像本MySQL时间处理秘籍啊!上周有个客人问我怎么优化查询,结果发现他直接在WHERE用DATE_FORMAT,索引全废了,真是气死个人。
咱这就掰扯掰扯这事儿。

时间格式化这事儿得这么看: DATE_FORMAT是挺好用的,上次上海那个项目,有个报表需要按'月-日'显示,直接DATE_FORMAT(current_timestamp, '%m-%d'),秒事办。
但!注意听! 千万别在WHERE子句里瞎用。
比如他写WHERE DATE_FORMAT(order_time, '%Y-%m-%d') = '2 02 3 -1 0-2 6 ',这绝对会触发全表扫描,索引?不存在的。
你想想,数据库得先跑一遍函数,再跟你比较,能不慢吗?这简直是自找麻烦。

STR_TO_DATE相对好点,特别是处理那些国外客户乱填的日期格式,STR_TO_DATE('2 6 /1 0/2 02 3 ', '%d/%m/%Y'),强行转成内部标准格式。
但这里有个坑,就是存储的时候尽量别存字符串,直接存DATE或者DATETIME类型,能省多少转换开销啊!我上次在深圳搞过一个系统,用户填日期的时候用STR_TO_DATE转,存进去还是字符串,结果每次查都要转一次,CPU直接干烧。
所以记住,输出格式化,存储用原生类型。

日期范围筛选才是核心中的核心: 这个我踩坑无数。
最推荐的就是用大于等于和小于(>=和<)。
上次北京那个电商项目,查'2 3 年1 0月'的数据,写WHERE order_time >= '2 02 3 -1 0-01 ' AND order_time < '2 02 3 -1 1 -01 ',直接走索引,快得飞起。
这比BETWEEN好用多了,你想想BETWEEN '2 02 3 -1 0-2 6 00:00:00' AND '2 02 3 -1 0-2 6 2 3 :5 9 :5 9 ',这要是中间加了秒或者毫秒,直接就漏了,用>=和<就没这毛病。
我测试过,用BETWEEN的查询时间比这个慢一倍不止。

动态范围也很实用,比如查昨天的数据,CURDATE()
INTERVAL 1 DAY <= log_time AND log_time < CURDATE>关键是记得CURDATE()和NOW()的区别,一个是只取日期,一个是日期+时间,用错可就乱套了。

那些让人头疼的坑: 时区问题简直是毒瘤。
我之前在杭州的项目,服务器是UTC,但用户在洛杉矶,他看数据就得转时区。
最好的办法就是统一用UTC存,展示的时候再转。
上次有个客户非要用当地时间存,结果节假日对不上,时区一变全乱,最后只能重做表结构。
血泪教训啊!
隐式类型转换也挺烦人。
比如你WHERE order_time = '2 02 3 -1 0-2 6 ',如果order_time是DATETIME类型,MySQL可能会猜你意思是STR_TO_DATE('2 02 3 -1 0-2 6 '),猜不对就全表扫。
所以要么显式转,要么确保类型一致。

边界精度也是老大难,比如2 3 :5 9 :5 9 可能包含毫秒,你用BETWEEN查'2 02 3 -1 0-2 6 2 3 :5 9 :5 9 '到'2 02 3 -1 0-2 7 00:00:00',如果2 3 :5 9 :5 9 .9 9 9 就在里面,就漏了。
所以要么用<下一个时间点的00:00,要么直接>=开始<结束。

时间函数还能这么用: DATEDIFF和TIMEDIFF上次算留存率的时候用得溜,比如DATEDIFF(last_login, CURDATE()) <= 3 0,找最近3 0天没登录的。
TIMEDIFF算上下班时长,贼方便。

DATE_ADD和DATE_SUB是神技,查过去一周的数据直接 DATE_SUB(NOW(), INTERVAL 7 DAY) >= created_at,简单粗暴。
想算3 0天后生日提醒?DATE_ADD(birthdate, INTERVAL 3 0 DAY)。

YEAR、MONTH、DAY这些更不用说了,分组统计必备。
上次算月度销售额,就是SELECT MONTH(order_time) AS month, SUM(amount) FROM orders GROUP BY month,一目了然。

WEEK和QUARTER也挺实用,比如按周看用户增长,按季度看收入,分析趋势特好。
时间戳转换UNIX_TIMESTAMP和FROM_UNIXTIME在跨语言对接时特重要,比如用Python脚本跑SQL,直接用整数时间戳比日期字符串方便多了。

总结一下吧: 核心就是WHERE别用函数,直接用范围筛选。
灵活用DATE_ADD、DATEDIFF这些。
存储统一用DATE/DATETIME。
注意时区、类型、边界、索引失效这些坑。
总之,写查询的时候多琢磨琢磨,别瞎写,否则等待你的就是"查询超时"四个大字。

行了,就说这么多,具体怎么用还得看你家数据情况。
我还在想那个时区转换的细节问题,得再查查...反正你看着办吧。