UNION
и UNION ALL
запросы могут превзойти эквивалентные запросы с использованием OR
-связанных предикатов при определенных обстоятельствах. Насколько мне известно, это частично связано с тем, что подзапросы UNION
могут выполняться параллельно, и поэтому они могут иметь свой собственный «подплан», специфичный для каждой части предиката OR
, который, вероятно, намного более оптимален из-за более простых применимых преобразований запросов ,Пусть Oracle преобразует OR-связанные предикаты в операции UNION ALL.
Но написание OR
-связанных предикатов обычно гораздо читабельнее и кратким, даже если факторинг подзапроса был применен к решению UNION ALL
. Мой вопрос: есть ли способ указать Oracle, что один дорогостоящий предикат OR
должен быть преобразован в операцию UNION ALL
? Если есть такой метод/метод, при каких обстоятельствах его можно применять (например, какие-либо ограничения должны присутствовать в столбцах, участвующих в предикатах, и т. Д.)? Пример:
CREATE TABLE a AS
SELECT 1 x, 2 y FROM DUAL UNION ALL
SELECT 2 x, 1 y FROM DUAL;
-- This query...
SELECT * FROM a
WHERE x = 1 OR y = 1
-- Is sometimes outperformed by this one, for more complex table sources...
-- Note: in my case, I can safely apply UNION ALL. I know the two predicates to
-- be mutually exclusive.
SELECT * FROM a
WHERE x = 1
UNION ALL
SELECT * FROM a
WHERE y = 1
Заметь, я знаю о /*+ USE_CONCAT */
намеке:
SELECT /*+ USE_CONCAT */ * FROM a
WHERE x = 1 OR y = 1
Но это, кажется, не производить то, что мне не нужно (не вынужденную UNION ALL
операции в плане выполнения):
-------------------------------------------
| Id | Operation | Name | E-Rows |
-------------------------------------------
| 0 | SELECT STATEMENT | | |
|* 1 | TABLE ACCESS FULL| A | 2 |
-------------------------------------------
Возможно, есть некоторые ограничения на этот намек? Для этого я имею Oracle 11g2.
Сколько строк (в% от всех строк) будет возвращено условие «x = 1 или y = 1» (в реальной таблице)? Как насчет использования подсказки 'PARALLEL' в запросе? –
@a_horse_with_no_name: На самом деле (реальное) условие имеет форму '(flag_function() = 1 и condition1) или (flag_function() = 0 и condition2)'. Два под-условия взаимно исключают друг друга в зависимости от PL/SQL 'flag_function()'. Я заметил, что Oracle создает гораздо лучший план для этого при использовании 'UNION ALL', а не при использовании' OR'. 'PARALLEL', вероятно, не поможет, так как количество данных в этом случае не так велико, но план сложный ... Кроме того, этот запрос выполняется очень часто в пользовательских сеансах.Я бы не хотел, чтобы слишком много ресурсов с подсказками 'PARALLEL' –
Эти запросы не эквивалентны. Вы должны использовать UNION вместо UNION ALL. Вы получите разные результаты, когда у вас есть строки, где x и y равны 1. – GriffeyDog