哪个更有效,where 子句或与百万多行表的连接?

Jer*_*oyd 22 join best-practices

我们运行的网站在一个表中具有 250 MM 的行,而在另一个表中,我们将其连接到大多数查询中的行不到 15 MM。

示例结构:

MasterTable (Id, UserId, Created, Updated...) -- 15MM Rows
DetailsTable (Id, MasterId, SomeColumn...) -- 250MM Rows
UserTable (Id, Role, Created, UserName...) -- 12K Rows
Run Code Online (Sandbox Code Playgroud)

我们必须定期对所有这些表进行一些查询。一种是抓取免费用户(~10k 免费用户)的统计数据。

Select Count(1) from DetailsTable dt 
join MasterTable mt on mt.Id = dt.MasterId 
join UserTable ut on ut.Id = mt.UserId 
where ut.Role is null and mt.created between @date1 and @date2
Run Code Online (Sandbox Code Playgroud)

问题是这个查询有时会运行很长时间,因为连接发生在 where 之前很久。

在这种情况下,使用 wheres 而不是 joins 或可能更明智where column in(...)吗?

gbn*_*gbn 22

对于现代 RDBMS,在性能和查询计划方面,“显式 JOIN”和“JOIN-in-the-WHERE”(如果所有 JOINS 都是 INNER)之间没有区别。

显式 JOIN 语法更清晰、更明确(见下面的链接)

现在,JOIN-before-WHERE 是逻辑处理而不是实际处理,现代优化器足够聪明来实现这一点。

您的问题很可能是索引。

请向我们展示这些表上的所有索引和键。和查询计划

注意:这个问题在 StackOverflow 上已经很接近了,因为它现在是重复的...... COUNT(1) vs COUNT(*) 也是另一个破灭的神话。

  • `join` 和 `where` 子句之间没有区别,这并不总是正确的。我一直在优化长时间运行的查询,有时使用 `where` 子句的查询性能比使用 `join` 的查询性能高 70 倍。如果就这么简单直接,生活将是彩虹和独角兽。这与一些古老的晦涩引擎无关 - 现在我正在研究 SQL 2012 中 `where` 子句的 70 倍优势。 (3认同)
  • @ajeh:我建议您的经历非常不典型。如果您有 x70 差异,则查询会遇到更大的问题:就是这么简单 (3认同)

Rol*_*DBA 7

您必须完全重构查询

尝试先执行 WHERE 子句,然后再执行 JOIN

Select Count(1) from DetailsTable dt
join (Select UserId,Id FROM MasterTable where
created between @date1 and @date2) mt on mt.Id = dt.MasterId 
join (Select Id FROM UserTable WHERE Role is NULL) ut
on ut.Id = mt.UserId;
Run Code Online (Sandbox Code Playgroud)

即使你在这个重构的查询上运行了一个 EXPLAIN 计划并且它看起来比你原来的更糟糕,无论如何都要尝试它。内部创建的临时表将执行笛卡尔连接,但这些表较小,无法使用。

我从这个 YouTube 视频中得到了这个想法

我在 StackOverflow 的一个非常复杂的问题中尝试了视频中的原则,并获得了 200 分的奖励。

@gbn 提到确保您拥有正确的索引。在这种情况下,请在 MasterTable 中索引创建的列。

试一试 !!!

更新 2011-06-24 22:31 EDT

您应该运行这些查询:

SELECT COUNT(1) AllRoles FROM UserTable;
SELECT COUNT(1) NullRoles FROM UserTable WHERE Role is NULL;
Run Code Online (Sandbox Code Playgroud)

如果 NullRoles X 20 < AllRoles(换言之,如果 NullRoles 小于表行的 5%),您应该在 UserTable 中创建一个非唯一索引 Role。否则,一个完整的 UserTable 表就足够了,因为查询优化器可能会排除使用索引。

更新 2011-06-25 12:40 EDT

由于我是 MySQL DBA,我的做事方法要求不要通过积极的悲观和保守来相信 MySQL 查询优化器。因此,我将尝试重构查询或创建必要的覆盖索引,以克服 MySQL 查询优化器隐藏的坏习惯。@gbn 的答案似乎更完整,因为 SQL Server 可能对评估查询有更多的“头脑清醒”。