我更喜欢使用实际上是内联连接的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函数,自联接等)
但我的问题是 - 通过这种方式查询数据库正在打击性能。
我还没有足够的数据来衡量差异,但我会在某个时候开始。
我想在进一步讨论之前找出答案。我不希望以后再回去重新编码所有内容以提高性能。
答案 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中的两个查询说的是非常不同的事情,只有在正确的数据模型假设到位时才产生相同的结果:
查找中使用的每个列都没有空约束和外键约束。
使用查找表的主键或唯一键。
可能在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中的一个提示。