编码内连接的两种方法中哪一种更快?

时间:2009-07-08 20:00:41

标签: sql-server sql-server-2005 tsql join

我更喜欢使用实际上是内联连接的t-sql代码,而不是在存储过程或视图末尾有一个很长的连接列表。

例如,我代码:

SELECT      PKey  ,    Billable, 
    (SELECT LastName  FROM Contact.dbo.Contacts WHERE (Pkey = Contacts_PKey)),
    (SELECT Description FROM Common.dbo.LMain WHERE (PKey= DType)),  
    (SELECT  TaskName  FROM  Common.dbo.LTask WHERE  (PKey =  TaskType)) ,  
    StartTime,  EndTime,  SavedTime
FROM   dbo.TopicLog   where  StartTime > '7/9/09'  ORDER BY  StartTime

而不是

SELECT t.PKey, t.Billable, c.LastName, m.Description, lt.TaskName, t.StartTime, t.EndTime, t.SavedTime
FROM dbo.TopicLog AS t     
inner join  Contact.dbo.Contacts as c   on  c.Pkey = t.Contacts_PKey and t.StartTime > '7/9/09'
inner join  Common.dbo.LMain  as m  on  m.PKey = t.DType
inner join  Common.dbo.LTask  as lt on lt.PKey = t.TaskType
ORDER BY t.StartTime

我更喜欢这种类型的语法,因为它在编写或调试时不那么容易混淆,特别是当有很多表正在连接或正在进行其他事情时(case语句,t-sql函数,自联接等)

但我的问题是 - 通过这种方式查询数据库正在打击性能。

我还没有足够的数据来衡量差异,但我会在某个时候开始。

我想在进一步讨论之前找出答案。我不希望以后再回去重新编码所有内容以提高性能。

8 个答案:

答案 0 :(得分:20)

第二个(实际的内部联接),通常。第一个(子查询)为每一行执行3次查询,但这通常由编译器管理,以便减少差异。

最好的:Check the query execution plans为你自己!

由于性能下降,我的猜测是你的表没有正确编入索引。您应该在所有主键上使用聚簇索引,在外键上使用非聚簇索引(用于进行连接的索引)。

我应该注意,当且仅当您在所有连接条件中具有匹配值时,这两个查询是等效的(即 - 始终返回主表中的所有行)。否则,如果没有匹配,您将从子查询中获得null。内部联接会主动过滤掉与连接条件不匹配的任何行。子查询方法实际上与左外连接等效(结果,而不是速度或执行)。

答案 1 :(得分:10)

第一种方法根本不是内连接,它是一个相关的子查询。 并且它们更像是左外连接而不是内连接,因为它们在没有匹配值时将返回NULL。

答案 2 :(得分:3)

第一个看起来像是一种与我联系的病态方式。我会避免它,如果没有其他原因这是不寻常的 - 一个经验丰富的SQL DBA看着它来维护它将花费一些时间来寻找为什么它编码的原因,当你没有真正的理由时想要查询。如果缺少数据,它的行为更像是外连接。

第二个例子看起来很正常。

你应该知道老式的内部连接方式是这样的:

SELECT t.PKey, t.Billable, 
 c.LastName, m.Description, lt.TaskName, 
 t.StartTime, t.EndTime, t.SavedTime
FROM 
 dbo.TopicLog as t, Contact.dbo.Contacts as c, 
 Common.dbo.LMain as m,  Common.dbo.LTask as lt   
WHERE c.Pkey = t.Contacts_PKey and t.StartTime > '7/9/09'
  AND m.PKey = t.DType
  AND lt.PKey = t.TaskType
ORDER BY  t.StartTime

据猜测,这相当于解析后的 field 上的现代“内部连接”语法。

正如另一个答案所说,如果您正在寻找更快的查询,首先要做的是检查表的索引是否已经整理好。然后查看查询执行计划。

答案 3 :(得分:1)

OP中的两个查询说的是非常不同的事情,只有在正确的数据模型假设到位时才产生相同的结果:

  1. 查找中使用的每个列都没有空约束和外键约束。

  2. 使用查找表的主键或唯一键。

  3. 可能在OP特定情况下这些假设是正确的,但在一般情况下,这些是不同的。

    正如其他人所指出的那样,子查询更像是外连接,因为它会为LastName,Description和Taskname列返回null,而不是完全过滤掉该行。

    此外,如果其中一个子查询返回多行,则会出错。

    就个人偏好而言,我更喜欢使用连接语法的第二个例子,但这是主观的。

答案 4 :(得分:1)

一般来说,简单子查询与连接的性能存在无差异 - 子查询要慢得多(因为SQL服务器必须循环遍历内部查询),这是一种常见的误解,但一般来说说这是根本不真实!在编译过程中,SQL Server会生成一个执行树,通常在这些树中,子查询等同于连接。

值得注意的是,你的两个查询在逻辑上并不相同并且为我产生了不同的结果,第二个查询实际上应该读取以下内容:(这仍然不相同,但更接近)

SELECT t.PKey, t.Billable, c.LastName, m.Description, lt.TaskName, t.StartTime, t.EndTime, t.SavedTime
FROM dbo.TopicLog AS t     
LEFT OUTER JOIN Contact.dbo.Contacts as c   on  c.Pkey = t.Contacts_PKey
LEFT OUTER JOIN Common.dbo.LMain  as m  on  m.PKey = t.DType
LEFT OUTER JOIN Common.dbo.LTask  as lt on lt.PKey = t.TaskType
WHERE t.StartTime > '7/9/09'
ORDER BY t.StartTime

在我的测试中,子查询产生了一个执行计划,其读取次数显着减少(15而不是1000),但cpu略高 - 平均执行时间大致相等。

值得注意的是,这并不总是这样(特别是在评估子查询中的函数时),而有时可能会因子查询而遇到问题。一般来说,只有在遇到性能问题时才最好担心这种情况。

答案 5 :(得分:0)

一般来说,子查询(即第一个示例)速度较慢,但​​优化和分析查询的最简单方法是通过特定数据库进行尝试,MS SQL Server提供了出色的分析和性能调优工具。

答案 6 :(得分:0)

许多SQL程序员完全不知道优化器经常将子查询解析为连接。两种查询都可能没有导致性能问题的原因。

查看执行计划!

答案 7 :(得分:0)

我认为第二个是执行得更快。 这背后的原因是通过使用别名(在您的示例中为t,c,m等)名称关系引擎可以轻松找到指向表位置的指针。

我认为这是sql tunning中的一个提示。