我有一个select(MS SQL),我正在加入一个最多有3个孩子的父母。如果任何一个孩子符合标准(Type<>'Done'),我想选择所有孩子。表现非常重要。
我试过
SELECT p.*,c.* FROM Parent p
INNER JOIN Child c ON p.Id=c.ParentId
WHERE p.Id IN (SELECT DISTINCT c.ParentId FROM Child c2 WHERE c2.ParentId=p.Id AND c2.Type<>'Done')
但内部选择通常会返回2000多个孩子,因此IN表现不佳。 我也试过EXISTS并计算:
SELECT p.*,c.* FROM Parent p
INNER JOIN Child c ON p.Id=c.ParentId
WHERE EXISTS(SELECT 1 FROM Child c2 WHERE c2.ParentId=p.Id AND c2.Type<>'Done')
SELECT p.*,c.* FROM Parent p
INNER JOIN Child c ON p.Id=c.ParentId
WHERE 0 < (SELECT COUNT(c2.Id) FROM Child c2 WHERE c2.ParentId=p.Id AND c2.Type<>'Done')
所有这些都会返回正确的结果但效果不佳。 我想我有所有必需的索引。
所有人都有其他选择吗?
答案 0 :(得分:1)
新答案:
那么我会用下面的查询创建一个临时表,并使用它们而不是嵌套的子查询,并尝试哪种组合最快。
更新
DECLARE @tmp TABLE(pid INT);
INSERT INTO @tmp(pid)
SELECT p.Id FROM Parent p
WHERE EXISTS (SELECT 1 FROM Child c WHERE c.ParentId=p.Id AND c2.Type<>'Done');
SELECT c.*, p.*
FROM @tmp t INNER JOIN Child c ON t.pid = c.ParentID INNER JOIN Parent p ON t.pid = p.Id
您也可以像声明Parent一样声明@tmp并填写整个表格。这样你可以避免使用Parent加入。但是,如果没有对所有可能的解决方案进行分析,就不可能说哪一个是最快的。
旧答案:
我认为您不需要加入Child表。这让你:
SELECT p.Id FROM Parent p
WHERE EXISTS (SELECT 1 FROM Child c2 WHERE c2.Type<>'Done' AND c2.Id = p.Id)
您也可以尝试
SELECT p.Id FROM Parent p
INNER JOIN Child c ON p.Id=c.ParentId
WHERE c.Type <> 'Done'
GROUP BY p.Id
或者
SELECT DISTINCT p.Id FROM Parent p
INNER JOIN Child c ON p.Id=c.ParentId
WHERE c.Type <> 'Done'
这些都应该是等价的。
答案 1 :(得分:0)
EXISTS变体通常应该是最快的。
假设您确实拥有所有相关索引,除了在临时表中准备数据之外,实际上没有办法优化此查询。您可以创建一个组合父表和子表的非规范化表。这应该是一次巨大的性能提升。
如果您永远不会删除或更新现有父记录,但只添加新记录,这是一个特别可行的解决方案。因为在这种情况下,您不会受到更新异常的影响。
如果您确实删除或更新了现有的父记录,这将使您的非规范化表格更新更加复杂。
答案 2 :(得分:0)
您也可以使用CTE:
;WITH Parents
AS
(
SELECT
p.*
FROM
[Parent] AS p
WHERE
EXISTS
(
SELECT
1
FROM
[Child] AS c
WHERE
p.ID = c.ParentID
AND c.[Type] <> 'Done'
)
)
-- Select all children and siblings...
SELECT
p.ID AS [ParentID]
,p.[Name]
,c.ID AS [ChildID]
,c.[Type]
FROM
Parents AS p
INNER JOIN [Child] AS c
ON p.ID = c.ParentID
查询计划非常小,可能对您有用。