假设我有下表
CREATE TABLE [dbo].[TestData](
[ID] [bigint] NOT NULL,
[InstanceID] [int] NOT NULL,
[Field] [int] NULL,
[UserID] [bigint] NOT NULL
) ON [PRIMARY]
GO
INSERT [dbo].[TestData] ([ID], [InstanceID], [Field], [UserID])
VALUES (1, 1, NULL, 1000),(2, 1, NULL, 1002),(3, 1, NULL, 1000),
(4, 1, NULL, 1003),(5, 2, NULL, 1002), (6, 2, NULL, 1005),
(7, 2, NULL, 1006),(8, 2, NULL, 1007),(9, 3, NULL, 1002),
(10, 3, NULL, 1006),(11, 3, NULL, 1009),(12, 3, NULL, 1010),
(13, 1, NULL, 1006),(14, 2, NULL, 1002),(15, 3, NULL, 1003)
GO
我搜索编写查询的最佳做法,使用 UserID
在两个实例之间获取完整的交叉数据行例如,InstanceID 1和2之间的相交的 UserIDs 是(1002,1006),以获得结果我用两种不同的方式来验证查询:
Select * From TestData
Where UserID in
(
Select T1.UserID From TestData T1 Where InstanceID = 1
Intersect
Select T2.UserID From TestData T2 Where InstanceID = 2
)
and InstanceID in (1,2) Order By 1
第二
Select * From TestData
Where UserID in
(
Select Distinct T1.UserID
From TestData T1 join TestData T2 on T1.UserID = T2.UserID
Where T1.InstanceID = 1 and T2.InstanceID = 2
)
and InstanceID in (1,2) Order By 1
结果将是
以上查询之一是获得结果的最佳方法吗?
答案 0 :(得分:0)
使用EXISTS
比使用IN
更好。使用IN
子查询时,将处理整个结果集。使用EXISTS
时,只需搜索它们即可匹配。至于你的问题,我认为INTERSECT
实现只是简单地进行连接,所以不应该有区别。
编辑:帖子Here表示,对于IN
vs EXISTS
,优化程序也会对它们进行同样的处理(截至2008年)。所以我的猜测以及我刚刚读到的内容归结为:它们将执行相同的操作,因为优化器知道。
答案 1 :(得分:0)
如果你要使用EXISTS语句,这是一个查询示例:
SELECT *
FROM TestData td
WHERE td.InstanceID IN (1, 2)
AND EXISTS
(SELECT 1
FROM TestData sub
WHERE td.UserID = sub.UserID
AND sub.InstanceID = 2)
AND EXISTS
(SELECT 1
FROM TestData sub
WHERE td.UserID = sub.UserID
AND sub.InstanceID = 1)
ORDER BY 1;
对于提供的样本数据,三种解决方案中的任何一种都没有明显的性能差异。但是,我同意Scotch的观点,即在特定情况下使用EXISTS语句将有助于提高IN语句的性能。
为提高性能,您可以做的最好的事情是使用PRIMARY KEY创建表。将ID字段设置为PRIMARY KEY将使性能提高50%,因为查询的最高成本是对数据进行排序。
答案 2 :(得分:0)
您也可以使用聚合和加入来执行此操作:
select td.*
from TestData td join
(select td.userid
from TestData
group by td.userId
having sum(case when InstanceId = 1 then 1 else 0 end) > 0 and
sum(case when InstanceId = 2 then 1 else 0 end) > 0
) td2
on td.userid = td2.userid
聚合的优点是having
子句使其在您可以表示的条件方面非常灵活。如果您有userId, InstanceId
的索引,那么效果最佳。
答案 3 :(得分:0)
该脚本由两个Index seek操作和一个Distinct排序操作使用。
SELECT ID, InstanceID, Field, UserID
FROM [dbo].[TestData] t
WHERE InstanceID IN(1, 2)
AND EXISTS (
SELECT 1
FROM [dbo].[TestData] t2
WHERE InstanceID IN(1, 2) AND t.UserID = t2.UserID
HAVING COUNT(DISTINCT t2.InstanceID) = 2
)
ORDER BY t.ID
OR
;WITH cte AS
(
SELECT ID, InstanceID, Field, UserId
,COUNT(*) OVER(PARTITION BY InstanceID, UserID) AS cntInstanceUser
FROM [dbo].[TestData] t
WHERE InstanceID IN(1, 2)
)
SELECT c.ID, c.InstanceID, c.Field, c.UserID
FROM cte c
WHERE EXISTS (
SELECT 1
FROM cte c2
WHERE c2.UserId = c.UserID
HAVING COUNT(*) != c.cntInstanceUser
)
ORDER BY c.ID
为了提高性能,请使用此索引:
CREATE INDEX x ON [dbo].[TestData](InstanceID, UserID) INCLUDE(Id, Field)
SQLFiddle上的演示