Порядок выполнения условий в SQL предложении 'where' - PullRequest
14 голосов
/ 04 декабря 2008

В моем предложении where есть ряд условий, таких как

WHERE 
d.attribute3 = 'abcd*'  
AND x.STATUS != 'P' 
AND x.STATUS != 'J' 
AND x.STATUS != 'X' 
AND x.STATUS != 'S' 
AND x.STATUS != 'D' 
AND CURRENT_TIMESTAMP - 1 < x.CREATION_TIMESTAMP

Какое из этих условий будет выполнено первым? Я использую оракула. ​​

Получу ли я эти данные в моем плане выполнения? (У меня нет полномочий делать это в БД, иначе я бы попробовал)

Ответы [ 6 ]

19 голосов
/ 04 декабря 2008

Вы уверены, у вас "нет полномочий" видеть план выполнения? Как насчет использования AUTOTRACE?

SQL> set autotrace on
SQL> select * from emp
  2  join dept on dept.deptno = emp.deptno
  3  where emp.ename like 'K%'
  4  and dept.loc like 'l%'
  5  /

no rows selected


Execution Plan
----------------------------------------------------------

----------------------------------------------------------------------------------
| Id  | Operation                    | Name         | Rows  | Bytes | Cost (%CPU)|
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |              |     1 |    62 |     4   (0)|
|   1 |  NESTED LOOPS                |              |     1 |    62 |     4   (0)|
|*  2 |   TABLE ACCESS FULL          | EMP          |     1 |    42 |     3   (0)|
|*  3 |   TABLE ACCESS BY INDEX ROWID| DEPT         |     1 |    20 |     1   (0)|
|*  4 |    INDEX UNIQUE SCAN         | SYS_C0042912 |     1 |       |     0   (0)|
----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("EMP"."ENAME" LIKE 'K%' AND "EMP"."DEPTNO" IS NOT NULL)
   3 - filter("DEPT"."LOC" LIKE 'l%')
   4 - access("DEPT"."DEPTNO"="EMP"."DEPTNO")

Как видите, это дает довольно много подробностей о том, как будет выполняться запрос. Это говорит мне, что:

  • условие "emp.ename like 'K%'" будет применено первым при полном сканировании EMP
  • тогда соответствующие записи DEPT будут выбраны с помощью индекса dept.deptno (с помощью метода NESTED LOOPS)
  • наконец, будет применен фильтр "dept.loc наподобие l%".

Этот порядок применения не имеет никакого отношения к тому, как предикаты упорядочены в предложении WHERE, как мы можем показать с помощью этого переупорядоченного запроса:

SQL> select * from emp
  2  join dept on dept.deptno = emp.deptno
  3  where dept.loc like 'l%'
  4  and emp.ename like 'K%';

no rows selected


Execution Plan
----------------------------------------------------------

----------------------------------------------------------------------------------
| Id  | Operation                    | Name         | Rows  | Bytes | Cost (%CPU)|
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |              |     1 |    62 |     4   (0)|
|   1 |  NESTED LOOPS                |              |     1 |    62 |     4   (0)|
|*  2 |   TABLE ACCESS FULL          | EMP          |     1 |    42 |     3   (0)|
|*  3 |   TABLE ACCESS BY INDEX ROWID| DEPT         |     1 |    20 |     1   (0)|
|*  4 |    INDEX UNIQUE SCAN         | SYS_C0042912 |     1 |       |     0   (0)|
----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("EMP"."ENAME" LIKE 'K%' AND "EMP"."DEPTNO" IS NOT NULL)
   3 - filter("DEPT"."LOC" LIKE 'l%')
   4 - access("DEPT"."DEPTNO"="EMP"."DEPTNO")
7 голосов
/ 04 декабря 2008

База данных будет решать, в каком порядке выполнить условия.

Обычно (но не всегда) сначала будет использоваться индекс, где это возможно.

6 голосов
/ 04 декабря 2008

Как уже было сказано, просмотр плана выполнения даст вам некоторую информацию. Однако, если вы не используете функцию стабильности плана, вы не можете полагаться на план выполнения, всегда оставаясь неизменным.

В случае запроса, который вы разместили, не похоже, что порядок оценки каким-либо образом изменит логику, поэтому я думаю, что вы думаете о эффективности. Вполне вероятно, что оптимизатор Oracle выберет эффективный план.

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

WITH subset AS
  ( SELECT /*+ materialize */
      FROM my_table
      WHERE CURRENT_TIMESTAMP - 1 < x.CREATION_TIMESTAMP
  )
SELECT *
  FROM subset
  WHERE 
  d.attribute3 = 'abcd*'  
  AND x.STATUS != 'P' 
  AND x.STATUS != 'J' 
  AND x.STATUS != 'X' 
  AND x.STATUS != 'S' 
  AND x.STATUS != 'D'

Подсказка "materialize" должна привести к тому, что оптимизатор сначала выполнит встроенный запрос, а затем отсканирует этот набор результатов для других условий.

Я не советую вам делать это как обычную привычку. В большинстве случаев простое написание запроса приведет к лучшим планам выполнения.

1 голос
/ 02 января 2009

Наконец, теория реляционных баз данных говорит, что вы не можете никогда зависеть от порядка выполнения предложений запроса, поэтому лучше не пытаться. Как уже говорили другие, оптимизатор на основе затрат пытается выбрать то, что он считает лучшим, но даже просмотр плана объяснения не будет гарантировать фактического используемого заказа. План объяснения просто говорит вам, что рекомендует CBO, но это еще не 100%.

Может быть, если вы объясните, почему вы пытаетесь это сделать, некоторые могут предложить план?

1 голос
/ 04 декабря 2008

Чтобы добавить к другим комментариям планы выполнения, в рамках модели затрат на основе процессора, введенной в 9i и используемой по умолчанию в 10g +, Oracle также выполнит оценку того, какой порядок оценки предикатов приведет к снижению вычислительных затрат, даже если это не влияет на порядок и способ доступа к таблице. Если выполнение одного предиката до того, как другой приведет к меньшему количеству вычислений предикатов, то такая оптимизация может быть применена.

См. Эту статью для более подробной информации: http://www.oracle.com/technology/pub/articles/lewis_cbo.html

Кроме того, Oracle даже не нужно выполнять предикаты, где сравнение с проверочным ограничением или определениями секций указывает, что строки все равно не будут возвращены.

Сложные вещи.

0 голосов
/ 24 сентября 2015

Хитрый вопрос. Просто столкнулся с той же дилеммой. Мне нужно упомянуть функцию в запросе. Сама функция делает другой запрос, поэтому вы понимаете, как это влияет на производительность в целом. Но в большинстве случаев у нас такая функция вызывается не так часто, если остальные условия выполняются первыми.

Ну, подумал, что было бы полезно опубликовать здесь еще одну статью по теме.

Следующая цитата скопирована с сайта Дональда Берлесона (http://www.dba -oracle.com / t_where_clause.htm ).

Подсказка order_predicates указана в предложении Oracle WHERE запрос и используется для указания порядка, в котором логические предикаты следует оценить.

В отсутствие упорядоченных_предикатов Oracle использует Следующие шаги для оценки порядка предикатов SQL:

  • Подзапросы оцениваются перед внешними логическими условиями в предложении WHERE.

  • Все логические условия без встроенных функций или подзапросов оцениваются в порядке, обратном порядку их нахождения в WHERE. предложение, причем последний предикат оценивается первым.

  • Булевы предикаты со встроенными функциями каждого предиката оцениваются в порядке возрастания их оценочных затрат на оценку.

...