我使用需要在我们的数据库上运行的2“IN”语句进行相当可怕的查询。首先是模式(本例简化):
CREATE TABLE [dbo].[SystemUser]
(
[SystemUserID] [int] IDENTITY(1,1) NOT NULL,
[FirstName] [nvarchar](50) NULL,
[Surname] [nvarchar](50) NULL
CONSTRAINT [PK_ApplicationUser] PRIMARY KEY CLUSTERED
(
[SystemUserID] ASC
)
)
GO
CREATE TABLE [dbo].[Group]
(
[GroupID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL
CONSTRAINT [PK_Group] PRIMARY KEY CLUSTERED
(
[GroupID] ASC
)
)
GO
CREATE TABLE [dbo].[GroupMembership]
(
[SystemUserID] [int] NOT NULL,
[GroupID] [int] NOT NULL
CONSTRAINT [PK_GroupMembership] PRIMARY KEY CLUSTERED
(
[SystemUserID] ASC,
[GroupID] ASC
)
)
GO
我想要做的是找到所有“SystemUser”记录,这些记录与没有GroupID列表中“Group”成员身份的SystemUserID列表相匹配。
因此,在一个查询中比较了两个独立的ID列表。我现在想到的最快的方法是:
SELECT SU.SystemUserID
FROM [dbo].[SystemUser] SU
LEFT JOIN
(
SELECT GM.SystemUserID
FROM [dbo].[GroupMembership] GM
WHERE GM.GroupID IN
(
1, 7, 8, 10, 32
)
) GM ON GM.SystemUserID = SU.SystemUserID
WHERE SU.SystemUserID IN
(
10, 61, 80, 93, 98
)
AND GM.SystemUserID IS NULL /* Not matched */
我有什么遗漏; “哪里不存在”检查会更有效率?或者你能想到两个列表更好的处理和过滤方式吗?
答案 0 :(得分:4)
假设SQL Server 2005或更高版本,
SELECT SU.SystemUserID
FROM [dbo].[SystemUser] SU
WHERE SU.SystemUserID IN
(
10, 61, 80, 93, 98
)
EXCEPT
SELECT GM.SystemUserID
FROM [dbo].[GroupMembership] GM
WHERE GM.GroupID IN
(
1, 7, 8, 10, 32
)
答案 1 :(得分:2)
使用IN
来封闭范围,而不是使用BETWEEN
(发出单独的查询):
SELECT SU.SystemUserID
FROM [dbo].[SystemUser] SU
LEFT JOIN
(
SELECT GM.SystemUserID
FROM [dbo].[GroupMembership] GM
WHERE GM.GroupID BETWEEN 1 AND 5
) GM ON GM.SystemUserID = SU.SystemUserID
WHERE SU.SystemUserID BETWEEN 10 AND 14
AND GM.SystemUserID IS NULL /* Not matched */
如果您的范围根本不是连续的,请创建临时表(或CTE),填充值,然后使用内部联接。
答案 2 :(得分:2)
通过重写查询文本可以解决很少的问题查询,您的查询也不例外。性能问题的罪魁祸首几乎总是缺少索引,你的同样也不例外。
SELECT SU.SystemUserID
FROM [dbo].[SystemUser] SU
LEFT JOIN
(
SELECT GM.SystemUserID
FROM [dbo].[GroupMembership] GM
WHERE GM.GroupID IN
(
1, 7, 8, 10, 32
)
) GM ON GM.SystemUserID = SU.SystemUserID
WHERE SU.SystemUserID IN
(
10, 61, 80, 93, 98
)
AND GM.SystemUserID IS NULL /* Not matched */
所以你需要:
GroupID
GroupMembership
上的索引
{li> SystemUserID
SystemUser
上的索引
SystemUserID
GroupMembership
上的索引(用于加入)你DDL(用于添加它!)显示你已经解决了2)和3),但没有解决1)。所以添加缺少的索引:
CREATE NONCLUSTERED INDEX idx_GroupMembership_GroupID ON GroupMembership(GroupID, SystemUserID)
根据经验法则:表格的多对多表格(leftId,rightId)总是需要(leftId, rightId)
上的索引和(rightId, leftId)
上的索引。
答案 3 :(得分:0)
根据我的经验,我更多地通过加入具有所需值的临时表而不是在值列表增加时使用IN来获得更好的结果。有100个值,我首先习惯这样,但可能会写两个并比较计划和统计数据。