ПРИМЕЧАНИЕ. Несмотря на то, что мой совет был верным много лет назад, оптимизатор Oracle улучшился, так что расположение здесь больше не имеет значения. Однако предпочтение UNION ALL
вместо UNION
всегда будет правильным, и переносимый SQL должен избегать зависимости от оптимизаций, которые могут быть не во всех базах данных.
Короткий ответ: вам нужно WHERE
перед UNION
, и вы хотите использовать UNION ALL
, если это вообще возможно. Если вы используете UNION ALL
, проверьте вывод EXPLAIN, Oracle может быть достаточно умным, чтобы оптимизировать условие WHERE
, если оно осталось после него.
Причина в следующем. В определении UNION
говорится, что если в двух наборах данных есть дубликаты, их необходимо удалить. Поэтому в этой операции есть неявный GROUP BY
, который имеет тенденцию быть медленным. Что еще хуже, оптимизатор Oracle (по крайней мере, 3 года назад, и я не думаю, что он изменился) не пытается проталкивать условия через GROUP BY
(неявные или явные). Поэтому Oracle приходится строить большие наборы данных, чем необходимо, группировать их и только потом приступать к фильтрации. Таким образом, предварительная фильтрация везде, где это возможно, официально является хорошей идеей. (Вот почему, кстати, важно по возможности помещать условия в WHERE
, а не оставлять их в предложении HAVING
.)
Кроме того, если вы знаете, что между двумя наборами данных не будет дубликатов, используйте UNION ALL
. Это похоже на UNION
тем, что он объединяет наборы данных, но не пытается дедуплицировать данные. Это экономит дорогостоящую операцию группировки. По моему опыту, довольно часто можно воспользоваться этой операцией.
Поскольку в UNION ALL
нет неявного GROUP BY
, возможно, оптимизатор Oracle знает, как протолкнуть через него условия. У меня нет Oracle для тестирования, поэтому вам нужно будет проверить это самостоятельно.
person
btilly
schedule
25.03.2011