Tsql 联合会比联合会更快吗?还是我的联合会很糟糕?
我有一个Tsql 联合会比联合会更快吗?还是我的联合会很糟糕?,tsql,sql-server-2008,Tsql,Sql Server 2008,我有一个Notes表,其中有一个uniqueidentifier列,用作数据库中其他各种表的FK(别担心,其他表上的uniqueidentifier列不是集群PK)。这些其他表表示业务对象的层次结构。作为一个简单的表示,假设我还有两个表: 线索(主键线索ID) 引号(PK QuoteID,FK LeadID) 在应用程序中显示的潜在客户中,我需要显示与潜在客户相关的所有注释,包括标记到属于该潜在客户的任何报价。就我所知,我有两个选择——要么是一个UNION ALL,要么是几个LEFT JOI
Notes
表,其中有一个uniqueidentifier
列,用作数据库中其他各种表的FK(别担心,其他表上的uniqueidentifier
列不是集群PK)。这些其他表表示业务对象的层次结构。作为一个简单的表示,假设我还有两个表:
- 线索(主键线索ID)
- 引号(PK QuoteID,FK LeadID)
潜在客户
中,我需要显示与潜在客户相关的所有注释,包括标记到属于该潜在客户的任何报价
。就我所知,我有两个选择——要么是一个UNION ALL
,要么是几个LEFT JOIN
语句。下面是它们的样子:
SELECT N.*
FROM Notes N
JOIN Leads L ON N.TargetUniqueID = L.UniqueID
WHERE L.LeadID = @LeadID
UNION ALL
SELECT N.*
FROM Notes N
JOIN Quotes Q ON N.TargetUniqueID = Q.UniqueID
WHERE Q.LeadID = @LeadID
或者
在现实生活中,我总共有五个可以附加注释的表,这个数字可能会随着应用程序的增长而增加。我已经在使用的uniqueidentifier
列上设置了非聚集索引,SQL Profiler说我不能再做任何改进,但当我对实际大小的测试数据集进行性能测试时,我得到以下数字:
-0.010秒UNION ALL
-0.744秒左连接
UNION
是不好的,而UNION-ALL
只是稍微好一点,但性能数据似乎不能证明这一点。诚然,UNION-ALL
SQL代码可能更难维护,但在这种性能差异下,它可能是值得的
因此,
UNION-ALL
在这里真的更好了吗?还是我在左连接上遗漏了一些东西,这会减慢速度?通过2次索引搜索,可能会很容易满足UNION-ALL
版本的要求<代码>或
可能导致扫描。执行计划是什么样子的
您是否也尝试过这样做以避免访问两次Notes
;WITH J AS
(
SELECT UniqueID FROM Leads WHERE LeadID = @LeadID
UNION ALL
SELECT UniqueID FROM Quotes WHERE LeadID = @LeadID
)
SELECT N.* /*Don't use * though!*/
FROM Notes N
JOIN J ON N.TargetUniqueID = J.UniqueID
根据我的经验,SQL Server对于包含
或的联接条件非常糟糕。在这种情况下,我也使用了UNION
s,我得到了与您类似的结果(可能是半秒而不是20秒)
谁说工会不好?特别是如果您使用UNION-ALL
,应该不会对性能造成影响,因为UNION
必须通过结果来只保留唯一的记录(实际上执行类似于distinct或group by
)的操作。UNION速度较慢,但UNION-ALL应该非常快,对吗?我可能错了,但我认为,若你们重写你们加入的版本,你们会得到更好的性能
SELECT N.*
FROM Notes N
LEFT JOIN Leads L ON N.TargetUniqueID = L.UniqueID AND L.LeadID = @LeadID
LEFT JOIN Quotes Q ON N.TargetUniqueID = Q.UniqueID AND Q.LeadID = @LeadID
WHERE Q.LeadID IS NOT NULL OR L.LeadID IS NOT NULL
您的第二个查询甚至不会给出正确的结果,因为它会将左连接转换为内部连接,请参见此处以了解语法错误的原因:
您是先运行UNION还是JOIN查询的?请记住,在SQL Server中,可以缓存查询,这样在第二次运行时可以获得更快的结果。在这两种情况下,我都运行了几次。任何查询的第一次运行肯定比后续运行慢,但我列出的那些时间的数字都是平稳的。+1-如果您知道数据完整性良好(即原始数据集中没有重复数据),则UNION ALL很好而且很快。检查执行计划表明,UNION ALL可以从多一个索引中获益……而且速度很快。与OR语句的联接确实会导致一次昂贵的索引扫描,尽管我不确定该结果的哪些部分与此处提供的内容相关……有什么提示吗?@Josh-只是出于兴趣,如果您将@LeadID
替换为常量(例如120
或您当前传递的任何内容),联接版本会发生什么情况你的扫描计划是一样的吗?对…忘了CTE!这将查询时间缩短到了0.007秒,并减少了代码数量,使其更易于维护。是的,无论是常量还是int
变量,都是相同的计划。至于*,我只在开发中使用它——所有的生产查询都有显式的列选择。哇,你说得对——它下降到了0.166秒。仍然比联盟慢,但肯定比最初的加入有很大的改进。我没有料到……为什么这样会更好呢?根据我对SQL server查询处理的记忆,JOIN
在WHERE
之前处理,因此在JOIN
阶段删除的行越多,查询就会越快。然而,我有点困惑,因为这里我们有外部连接,而不是内部连接。也许是[NOT]NULL
比=
快得多,我不能确定。。。我在Mysql中尝试过类似的查询,它也显示了相同的结果(此查询比原始查询快5-7倍),但它确实产生了正确的结果。我怀疑区别在于我在WHERE子句中使用的是OR而不是AND。在链接中,和ed条件会导致结果集受到限制,因此会“转换”为内部联接。我不认为这和这个场景是一回事,是吗?
SELECT N.*
FROM Notes N
LEFT JOIN Leads L ON N.TargetUniqueID = L.UniqueID AND L.LeadID = @LeadID
LEFT JOIN Quotes Q ON N.TargetUniqueID = Q.UniqueID AND Q.LeadID = @LeadID
WHERE Q.LeadID IS NOT NULL OR L.LeadID IS NOT NULL