Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 什么';从一个表中获取相交数据的最佳方法是什么?_Sql_Sql Server_Database_Performance - Fatal编程技术网

Sql 什么';从一个表中获取相交数据的最佳方法是什么?

Sql 什么';从一个表中获取相交数据的最佳方法是什么?,sql,sql-server,database,performance,Sql,Sql Server,Database,Performance,假设我有下表 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

假设我有下表

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和InstanceID 2之间相交的用户ID是(10021006),为了获得查询结果,我使用两种不同的方式进行查询,如下所示:

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
因此,结果将是肯定的


是上述查询中的一种,是获得结果的最佳方式吗???

使用
存在
比在
中使用
更好。在
子查询中使用
时,将处理整个结果集。当
存在时
,它只会在找到匹配项时进行搜索。至于你的问题,我认为,
INTERSECT
实现只是简单地进行了连接,所以应该没有区别


编辑:一篇帖子说,对于
中的
存在的
,优化器也会同样对待它们(从2008年开始)。因此,我的猜测和我刚刚读到的内容大致可以归结为:它们将执行相同的操作,因为优化器知道。

如果要使用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语句将有助于提高语句中的性能


要提高性能,最好的方法是使用主键创建表。将ID字段设置为主键将提高50%的性能,因为查询的最高成本是对数据进行排序。

您也可以通过聚合和联接来实现这一点:

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
上有一个索引,那么性能会最好。脚本由两个索引查找操作和一个不同排序操作使用

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

为了提高性能,请使用此索引:

CREATE INDEX x ON [dbo].[TestData](InstanceID, UserID) INCLUDE(Id, Field)

演示

在简化阶段,查询优化器并不总是以相同的方式处理和存在。即使在测试上述代码时,我在EXISTS和IN之间进行测试时也收到了两种不同的计划。但是,当我在ID字段上创建主键时,我从查询优化器获得了相同的结果,而没有对代码进行任何额外更改。EXISTS肯定是两者中比较安全的。我想我只是假设ID字段上有一个主键。我倾向于使用
EXISTS
,但我认为那里的许多优化人员足够聪明,能够理解您的意思。您确定使用聚合将获得最佳性能吗?因为我认为使用“intersect”会更好。。你能解释一下吗?@AmrBadawy。不,我不确定哪一个性能最好。为此,您需要测试不同的解决方案。我更喜欢聚合解决方案,因为它通常解决“集合中的集合”问题(这只是这类问题的一个例子)。
CREATE INDEX x ON [dbo].[TestData](InstanceID, UserID) INCLUDE(Id, Field)