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