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说我不能再做任何改进,但当我对实际大小的测试数据集进行性能测试时,我得到以下数字:

  • UNION ALL
    -0.010秒
  • 左连接
    -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