问题描述
这是我的桌子
CREATE TABLE log_table (
`user_id` VARCHAR(5),`date_time` DATETIME,`event_name` VARCHAR(10),`trivial` int
);
INSERT INTO log_table
(`user_id`,`date_time`,`event_name`,`trivial`)
VALUES
('001','2020-12-10 10:00:02','c',3),('001','2020-12-10 10:00:01','b',9),'2020-12-10 10:00:40','e',2),'2020-12-10 10:00:20','d',6),'2020-12-10 10:00:00','a',1),('002','2020-12-09 10:00:10','C','2020-12-10 10:00:50','D',0),'A','2020-12-10 10:00:09','B',4);
(创建于 DB Fiddle)
我想找到一个触发事件名称的人(任何人)并检索该用户当天的所有记录。
user_id | 日期时间 | 事件名称 | 琐碎 | trivial_new |
---|---|---|---|---|
001 | 2020-12-10 10:00:00 | 一 | 1 | 13 |
001 | 2020-12-10 10:00:01 | b | 9 | 19 |
001 | 2020-12-10 10:00:02 | c | 3 | 21 |
001 | 2020-12-10 10:00:20 | d | 6 | 20 |
001 | 2020-12-10 10:00:40 | e | 2 | 11 |
002 | 2020-12-09 10:00:02 | A | 2 | 15 |
002 | 2020-12-10 10:00:09 | B | 4 | 15 |
002 | 2020-12-10 10:00:10 | C | 9 | 15 |
002 | 2020-12-10 10:00:50 | D | 0 | 13 |
这是我的代码:
SELECT t_left.*
FROM log_table AS t_left
RIGHT JOIN (SELECT user_id,date_time
FROM log_table
WHERE BINARY event_name = 'B'
LIMIT 1) AS t_right
ON t_left.user_id = t_right.user_id
AND Substring_index(t_left.date_time,' ',1) =
Substring_index(t_right.date_time,1)
ORDER BY date_time
在右表中,只有一条记录满足event_name
为B
的条件,即id为002的用户。然后我将其与左表连接在他们的 user_id 相等且日期为 2020-12-10
的条件下,删除具有不同 id 的其他用户 001
,以及在 2020-12-10
之外发生事件的同一个人的记录。>
一切正常。
然后我修改了我的代码以检查它是否会如我所愿(确实如此,请参阅 here):
SELECT t_left.*
FROM log_table AS t_left
RIGHT JOIN (SELECT user_id,date_time
FROM log_table
WHERE BINARY event_name = 'B'
LIMIT 1) AS t_right
ON t_left.user_id = t_right.user_id
WHERE Substring_index(t_left.date_time,1) =
Substring_index(t_right.date_time,1)
ORDER BY date_time
在这种情况下,我只是通过一个条件连接表格并过滤该用户的日期以获得正确的记录。
我阅读了一些答案 here 和 here 和 here,其中大多数示例都以常量为条件,有些人说 join 会更快,而其他人则说编译器会优化子句和因此速度将是相同的。
我想知道在我的情况下第一个会更快吗?
有什么在线平台可以比较速度吗?
解决方法
ON
应该用于说明表格之间的关系。
WHERE
应该用于过滤。
对于普通的 JOIN
(INNER JOIN
),它们的实现方式相同。
对于左/右,它们可能会产生很大的不同。
,如果假设第二个查询是最终查询结构,则您不再需要使用 RIGHT JOIN
,尤其如此,因为您匹配 WHERE
中的日期而不是 {{ 1}}... 有效地取消右连接(或左连接)。实际上,由于您正在对仅提取右侧表的某些数据的子查询进行右连接,因此几乎没有任何理由进行右连接,如果您改为进行左连接,结果会出现更多差异。此外,根据我的经验,ON
(JOIN
) 通常比左/右连接快得多。
另一件事是,索引在性能方面有很大的不同。在您当前的示例中,没有索引,因此我建议您这样做。我从@Rick James 的 page here 那里学到了很多关于索引的知识。
这是一个基于您的示例日期的小提琴,包括您的原始尝试和其他一些:
INNER JOIN
RIGHT JOIN .. ON ... AND
RIGHT JOIN .. ON ... WHERE
LEFT JOIN .. ON ... AND
- 添加索引
-
LEFT JOIN .. ON ... WHERE
前后索引。
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=1b244deb6fad0dda0bf4aaf701e6bac2
PS:在小提琴中,我将日期提取更改为使用 EXPLAIN
。