【问题标题】:select from two independent table based on not exist a row in a third table joining them根据第三个表中不存在加入它们的行从两个独立表中选择
【发布时间】:2020-09-18 23:01:19
【问题描述】:

我有一个关于 SQL 查询的问题。 我需要两个独立表中的所有行,这些表没有将它们连接到第三个表中的行。查询以这种方式工作,但性能很差。

现在我的查询如下所示:

SELECT s.id, 
       u.id 
FROM   table1 s, 
       table2 u 
WHERE  NOT EXISTS
       ( 
              SELECT * 
              FROM   table3 sj 
              WHERE  sj.s_id=s.id 
              AND    sj.u_id=u.id
       )

table3 上的键是:

ALTER TABLE `table3`
    ADD PRIMARY KEY (`id`),
    ADD KEY `s_id` (`s_id`),
    ADD KEY `u_id` (`u_id`);

table1 有 4 行, table2 有 80.000 行, table3 有 30.000 行

任何想法如何优化它? 现在查询最多需要 20 分钟才能给出结果。

编辑: 关于 20 分钟 -> 我忘了在table3(u_id) 上设置密钥 设置密钥后,只需几秒钟。太好了。

【问题讨论】:

  • 感谢您的反对,但我认为我的问题甚至我的 SQL 查询对于曾经接触过 SQL 的每个人来说都非常清楚。我还应该为三个只有 ID 的表提供 CREATE TABLE 代码?
  • 请注意,'EXITS' 不是 MySQL 中公认的术语
  • 此外,除了所有相关表的 SHOW CREATE TABLE 语句之外,有关查询性能的问题总是需要对给定查询的 EXPLAIN

标签: mysql sql join subquery query-optimization


【解决方案1】:

在我看来,您的查询是做您想做的事情的正确方法。我只是将老式的隐式连接重写为显式的cross join(但这在语义上是等价的)。

为了提高性能,您需要在table3(s_id, u_id) 上建立索引。

但是,您需要记住,交叉连接表会生成大约 24 亿行的派生表,因此not exists 条件下的数据库还有很多工作要做。

如果siduid在源表中不是唯一的,那么你可以在交叉加入之前进行去重:

select ...
from (select distinct id from table1) s
cross join (select distinct id from table3) u 
where not exists (...)

【讨论】:

  • 如果 sid 和 uid 不是唯一的 -> 你的意思是 table3 中的行有好几次相同的 sid 和 uid -> 不是进度表,所以每个组合只存在一行.
  • 关于索引 -> 每列是索引还是多列索引?我只是在阅读有多个列索引,直到现在对我来说这是一个模糊的话题
  • @ChrisMaster:是的,我的意思是 table3 上的多列索引。我所说的不是唯一的,是指源表(table1 和 table2)中的唯一。
  • 好的,我明白了,在 sourcetable 中它的 auto_increment/unique/primary。伟大的。谢谢。
  • 从两个单索引更改为多列索引后,请求时间减少了一半。
猜你喜欢
  • 2018-05-02
  • 1970-01-01
  • 2017-11-20
  • 1970-01-01
  • 1970-01-01
  • 2021-02-16
  • 1970-01-01
  • 2021-06-18
  • 2014-07-27
相关资源
最近更新 更多