SQL-запрос со сложным подзапросом - PullRequest
3 голосов
/ 05 августа 2010

У меня есть два стола, Foo и Bar. Foo содержит внешний ключ к первичному ключу Bar (bar_id). Bar структурирован так, чтобы разрешить отношения родитель / потомок к себе через внешний ключ (bar_parent_id) к другой записи в Bar. Это отношение ограничено, так что любая запись Bar, у которой есть родитель, сама не может быть родительской. Однако у любого данного родителя может быть несколько детей.

В моем запросе необходимо выбрать все записи в Foo, которые соответствуют заданной записи в Bar, а также любых родителей, детей или братьев 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. Это упрощенная версия реального запроса. На самом деле у него есть второй, идентичный подзапросу к другой таблице, которая имеет те же отношения self / parent / child, что и Bar.

Ответы [ 3 ]

2 голосов
/ 05 августа 2010

Вы можете попробовать, но я не уверен в правильности

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  
1 голос
/ 05 августа 2010

Попробуйте это:

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 голосов
/ 06 августа 2010

ИЛИ часто замедляют запросы 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
...