现在有个功能需要统计每个用户的首单。自己写的 sql 不太满意,希望大家能指点下。
这是我写的 sql
SELECT * FROM order WHERE create_time IN (
		SELECT min( create_time ) create_time FROM
			order WHERE
			order_status IN ( 'PRE_DELIVER', 'PRE_ACCEPT', 'AFTER_DELIVER' ) 
			AND user_id in (1,2,3,4) AND deleted = 0 GROUP BY user_id 
	) 
GROUP BY user_id
我是先查询出每个用户第一单的时间,在通过时间去查询对应的订单。
但想不出怎么去优化,只能请教下大家,希望能给一些思路
|      1linauror      2020-04-23 10:18:39 +08:00 ` SELECT *,MIN(create_time) FROM order WHERE order_status IN ( 'PRE_DELIVER', 'PRE_ACCEPT', 'AFTER_DELIVER' ) AND user_id in (1,2,3,4) AND deleted = 0 GROUP BY user_id ` 试试这个呢 | 
|      2kamisama      2020-04-23 10:21:17 +08:00 这种最好把表索引也发出来 | 
|      3dongisking      2020-04-23 10:27:17 +08:00 via Android 敢用子查询的都是菜鸡吧 | 
|  |      5zhuzhibin      2020-04-23 10:36:30 +08:00 via iPhone @dongisking 有必要吗?人家是请教问题 ?你在干嘛? | 
|  |      6zhuzhibin      2020-04-23 10:36:30 +08:00 via iPhone @dongisking 有必要吗?人家是请教问题 ?你在干嘛? | 
|      7liubx OP @kamisama 索引是`user_id`,`create_time``sale_order_no``deleted`这四个字段 | 
|      8liubx OP @dongisking 嗯,数据库确实不熟,大佬指点下啊 | 
|      9newtype0092      2020-04-23 10:42:22 +08:00 @dongisking 多干两年接触点复杂业务再来说话。 | 
|  |      10CrazyMoon      2020-04-23 10:45:50 +08:00 不太懂怎么优化,不过感觉这个 sql 的正确性可能有问题。。如果有多订单同时创建的话,按照 create time 取会取出多余的订单 | 
|  |      11moonsola      2020-04-23 11:06:20 +08:00 要我就选择在用户表里加个字段:first_order_id | 
|  |      12lifespy      2020-04-23 11:09:27 +08:00 | 
|  |      14lifespy      2020-04-23 11:11:48 +08:00 如果数据量特别大的话,建议专门独立一个表出去存储 | 
|      15mwiker      2020-04-23 11:15:38 +08:00 SELECT t.* FROM order t INNER JOIN ( SELECT user_id, min(create_time) create_time FROM order WHERE order_status IN ( 'PRE_DELIVER', 'PRE_ACCEPT', 'AFTER_DELIVER' ) AND user_id in (1,2,3,4) AND deleted = 0 GROUP BY user_id ) t2 ON t.user_id = t2.user_id AND t.create_time = t2.create_time | 
|  |      16int11      2020-04-23 11:15:51 +08:00 订单 id 是自增的话,通过 id 大小去判断要好一些 | 
|      17mwiker      2020-04-23 11:17:59 +08:00 搞个 mysql8.0,有开窗函数做这些就很简单了 | 
|      18usdf      2020-04-23 11:18:55 +08:00 如果是 mysql5.7 版本以下的 | 
|  |      19tinybaby365      2020-04-23 11:19:05 +08:00 order 表有多大,每个用户平均有几单?如果你是在线上 db 操作,我有点担心你这一次性把所有用户首单查出来的操作把会把你的 db 搞挂。如果是操作 OLAP 的 DB,那无所谓啦。 | 
|      20usdf      2020-04-23 11:21:03 +08:00 SELECT * FROM order WHERE order_status IN ( 'PRE_DELIVER', 'PRE_ACCEPT', 'AFTER_DELIVER' ) AND user_id in (1,2,3,4) AND deleted = 0 GROUP BY user_id ORDER BY order_id ) | 
|      22wuzhizuiguo      2020-04-23 11:24:16 +08:00 | 
|  |      24DoUSeeMe      2020-04-23 11:26:52 +08:00 这个问题类似于获取分类前 N 条记录,你这里的 user 就是类,可以去查一查。 如果你要具体的优化语句,可以把表的代码复制出来,我比较懒,懒得去新建一个 | 
|  |      25levelworm      2020-04-23 11:27:29 +08:00 不能用窗口函数吗?不能的话这个不知道行不行 select * from ( select * from order order by user_id, time asc ) as x group by cid | 
|  |      26Nostalgiaaaa      2020-04-23 11:27:52 +08:00 试一下  partition by,解决这类首单,首次,最后一次的问题 简单搜了一下应该是一个类似的问题 https://stackoverflow.com/questions/18987727/sql-query-using-partition-by SELECT * FROM (SELECT * , ROW_NUMBER() over( partition by user_id ORDER BY create_time DESC ) AS rank FROM order WHERE order_status IN ( 'PRE_DELIVER', 'PRE_ACCEPT', 'AFTER_DELIVER' ) AND user_id IN (1,2,3,4) AND deleted = 0 ) WHERE rank = 1 另外,分析型 sql 建议做成定时任务定时刷新,比如半小时一次,实时查意义不大并且性能问题很严重 | 
|  |      27levelworm      2020-04-23 11:30:08 +08:00 @Nostalgiaaaa 他这个估计版本比较老用不了窗口函数,我猜测 | 
|      28iffi      2020-04-23 11:45:15 +08:00 可用 join | 
|      30liubx OP  1 @Nostalgiaaaa 嗯,谢谢回复。现在决定做成定时任务了 | 
|  |      31icchux      2020-04-23 11:47:02 +08:00 @levelworm 这个可以  我上午刚用这个子查询的方法 统计一些东西 但这个是慢查询 数据量大的时候特别慢。。。。。。mysql 低版本对于这种统计要求真的烦心 | 
|  |      36ooyy      2020-04-23 12:01:07 +08:00 sql 查询改动小,性能要看表数据量 with t as ( select *, ROW_NUMBER() over (partition by user_id ORDER BY create_time DESC ) AS rn from order inner join c_order on order.id = c_order.id ... ) select * from t where rn = 1 and a.order_status IN ( 'PRE_DELIVER', 'PRE_ACCEPT', 'AFTER_DELIVER' ) and ... | 
|  |      37seanseek      2020-04-23 13:09:54 +08:00 能不能按照 id 和时间排序,然后再去个重? | 
|      38jeff0819      2020-04-23 15:11:18 +08:00 建议中间表,写个脚本跑出来再去查 | 
|  |      39seanseek      2020-04-23 16:37:15 +08:00 group by user_id 可以 |