2010-05-20 1 views
3

У меня есть таблица foo и табличная панель, где каждый foo может иметь панель (а панель может принадлежать нескольким foos).Условные подзапросы оптимизированы, если условие ложно?

Теперь мне нужно выбрать все foos с баром. Мой sql выглядит так:

SELECT * 
    FROM foo f 
WHERE [...] 
    AND ($param IS NULL OR (SELECT ((COUNT(*))>0) 
          FROM bar b 
          WHERE f.bar = b.id)) 

с заменой $ param во время выполнения.

Вопрос: будет ли выполняться подзапрос, даже если параметр равен null или будет ли dbms оптимизировать подзапрос?

Мы используем mysql, mssql и oracle. Есть ли разница между ними в отношении вышеизложенного?

ответ

2

Это зависит. Если вы каждый раз передаете этот запрос в СУБД, тогда компилятор должен понимать, что ему не нужно вызывать подзапрос. Если это статическая процедура, то это зависит от того, как компилятор хранит план выполнения. Если он сохраняет план выполнения при первом вызове процедуры и первый раз, когда он называется $ param, не является нулевым, то он может фактически вызвать подзапрос каждый раз, когда выполняется процедура.

На другой ноте, вы должны рассмотреть Exists вместо COUNT (*) для этого типа проверки

Select .. 
From foo f 
Where .... 
    And ($param Is Null 
      Or Exists (
         Select 1 
         From bar b 
         Where b.id = f.bar 
         )) 
1

В этом случае я рекомендую делать оптимизацию самостоятельно в коде приложения, а не полагаться на оптимизатор из трех различных РСУБД, чтобы последовательно обрабатывать это так, как вы хотите.

Если $ param является нулевым, просто выберите из таблицы foo. Если нет, присоединитесь к столбику.

псевдокода:

if ($param is null) 
    SELECT * 
    FROM foo f 
    WHERE [...] 
else 
    SELECT distinct f.* 
    FROM foo f 
    inner join bar b on f.bar = b.id 
    WHERE [...] 
end if 
+0

Я не рекомендую этот подход, ради что вы будете герметизирующего три (или больше) синтаксис баз данных, который будет расходиться. IE: MySQL поддерживает LIMIT, который ни SQL Server, ни Oracle не делают - SQL Server использует TOP, в то время как Oracle использует ROWNUM. Или используйте технологию абстракции базы данных, такую ​​как Hibernate/etc, чтобы вы не обременялись кодированием самого SQL или сами использовали хранимую процедуру/функцию каждой базы данных для кодирования и настройки запросов для каждого. –

+0

Чтобы уточнить, мой псевдокод 'if ... else ... end if' предназначен для использования в прикладном уровне, а не в SQL. Я не рекомендую добавлять сложность SQL, на самом деле я думаю, что SQL должен быть упрощен. Основной момент, который я делал, заключается в том, что если у вас есть простой условный параметр, такой как '$ param is null ', вам, вероятно, лучше переместить это из SQL и в прикладной уровень. Это должно работать независимо от того, использует ли OP Hibernate и т. Д. Или пишет прямой SQL. –

+0

Да, мы используем слой абстракции db, домашний, с так называемыми именованными запросами, которые записываются в xml-файлы и доступны из нашего кода. Параметры передаются из кода, а sql генерируется уровнем абстракции. Поэтому самый простой способ - использовать вид ($ param - null || $ param == ...), как я сделал в примере. Единственный недостаток до сих пор заключался в том, что полученный sql загроможден нулевым значением null ... что мешает отладке бит, но до сих пор никогда не было проблемой производительности - до сих пор, когда мне нужно условное соединение. –