如果符合条件,请选择所有孩子

时间:2014-11-04 10:15:14

标签: sql sql-server select parent-child

我有一个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')

所有这些都会返回正确的结果但效果不佳。 我想我有所有必需的索引。

所有人都有其他选择吗?

3 个答案:

答案 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

查询计划非常小,可能对您有用。