2010-08-05 115 views
3

我有两个表,Foo和Bar。 Foo包含Bar的主键(bar_id)的外键。 Bar的结构允许父/子关系通过外键(bar_parent_id)与Bar中的另一条记录进行关联。这种关系是有限的,任何具有父母的条形记录本身都不能成为父母。但是,任何给定的父母可以有多个孩子。带有复杂子查询的SQL查询

我的查询需要选择Foo中与Bar中的给定记录匹配的所有记录以及酒吧的任何父母,孩子或兄弟姐妹。下面的查询工作,但有点慢。有没有什么办法可以让它运行得更快?

SELECT f.field1, f.field2 
FROM Foo f 
WHERE f.bar_id IN (
    SELECT bar_id 
    FROM Bar 
    WHERE bar_id = @bar_id OR 
    bar_parent_id = @bar_id OR 
    bar_id = (SELECT bar_parent_id FROM Bar WHERE bar_id = @bar_id) OR 
    bar_parent_id = (SELECT bar_parent_id FROM Bar WHERE bar_id = @bar_id AND bar_parent_id > 0) 
) 

P.S.这是真正查询的简化版本。它实际上与另一个与Bar具有相同自/父/子关系的表具有相同的子查询。

+0

您是否尝试过使用exists代替为您的WHERE子句? – JNK 2010-08-05 17:52:56

回答

1

试试这个:

SELECT f.field1, f.field2 
    FROM Foo f 
WHERE EXISTS(SELECT NULL 
       FROM BAR b 
       WHERE b.bar_id = f.bar_id 
       AND ( @bar_id IN (b.bar_id, b.bar_parent_id) 
         OR EXISTS(SELECT NULL 
            FROM BAR x 
            WHERE x.bar_parent_id = b.bar_id 
            AND x.bar_id = @bar_id) 
         OR EXISTS(SELECT NULL 
            FROM BAR y 
            WHERE y.bar_parent_id = b.bar_parent_id 
            AND y.bar_id = @bar_id 
            AND y.bar_parent_id > 0)) 
+0

+ 1 for @bar_id IN(b.bar_id,b.bar_parent_id)。我从来没有想到这个 – 2010-08-05 17:58:46

+0

真棒查询!我不知道IN语法是可能的。可悲的是,这仍然比我原来的查询慢一点。 – 2010-08-05 20:58:34

+0

@NorwegianWood:这是因为OR – 2010-08-05 21:00:35

2

你可以试试,但我不知道是否正确

SELECT 
    f.field1, f.field2 
FROM 
    foo f 
    LEFT JOIN bar b 
    LEFT JOIN bar bParent 
    ON b.parent_id = bParent.bar_id 
    LEFT JOIN bar bChildren 
    ON b.bar_id = bChildren.Parent_id 
WHERE 
    b.bar_id = @bar_id 
    or 
    bParent.bar_id = @bar_id 
    or 
    bChildren.bar_id = @bar_id 
+0

你会想DISTINCT - 加入风险复制记录。 – 2010-08-05 18:00:15

+0

第一次连接需要一个ON子句。无论如何,这个比我现有的要慢很多。 – 2010-08-05 20:59:15

0

手术室经常SQL查询减缓。这可以表现更好的替代方法是工会单独的查询结果,就像这样:

SELECT f.field1, f.field2 FROM Foo f where f.bar_id = @bar_id 
UNION 
SELECT f.field1, f.field2 FROM Foo f 
JOIN Bar b on f.bar_id = b.bar_id and @bar_id = b.bar_parent_id 
UNION 
SELECT f.field1, f.field2 FROM Foo f 
JOIN Bar bsib on f.bar_id = bsib.bar_id 
JOIN Bar b on bsib.bar_parent_id = b.bar_parent_id and @bar_id = b.bar_id 
UNION 
SELECT f.field1, f.field2 FROM Foo f 
JOIN Bar bpar on bpar.bar_id = f.bar_id 
JOIN Bar b on bpar.bar_id = b.bar_parent_id and @bar_id = b.bar_id