Порядок выполнения условий в предложении SQL 'where'

У меня есть набор условий в моем предложении 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

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

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


person sarego    schedule 04.12.2008    source источник
comment
Какой инструмент вы используете для запуска SQL?   -  person    schedule 05.12.2008
comment
Возможно, не хватает сути вашего вопроса. Почему вас волнует, в каком порядке они выполняются?   -  person WW.    schedule 18.12.2008


Ответы (6)


Вы уверены, что у вас "нет полномочий" просматривать план выполнения? А как насчет использования 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")
person Tony Andrews    schedule 04.12.2008

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

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

person Greg    schedule 04.12.2008
comment
Вы думаете о RBO, более современный CBO не предпочитает индексы. - person ; 05.12.2008
comment
Он предпочитает их, когда они лучше :) По моему опыту, это нормально. - person WW.; 18.12.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'

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

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

person Dave Costa    schedule 04.12.2008
comment
Я бы выделил ваше предостережение жирным шрифтом. Если у него проблемы с составлением плана объяснений ... учить его подсказкам, наверное, уже не к чему. - person ; 05.12.2008

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

Подробнее см. В этой статье: http://www.oracle.com/technology/pub/articles/lewis_cbo.html

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

Сложный материал.

person David Aldridge    schedule 04.12.2008

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

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

person Stew S    schedule 02.01.2009

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

Что ж, подумал, что будет полезно разместить здесь еще одну статью по теме.

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

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

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

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

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

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

person Nikolay Antipov    schedule 24.09.2015
comment
Все пункты списка ложны в той степени, в которой они вообще имеют какой-то смысл. Логический предикат - это ерунда - все предикаты оцениваются как истинные или ложные, поэтому другого вида нет. - person David Aldridge; 24.09.2015
comment
О, также предложение order_predicates было задокументировано как идущее после предложения WHERE, но, как и все другие подсказки, идет сразу после SELECT, так что эта статья не отражает какой-либо практический опыт использования подсказки. Я также нашел ссылку, в которой говорится, что это применимо только в контексте предикатов одной таблицы для каждой таблицы, к которой осуществляется доступ. Он также устарел в 10g, а поддержка 9.2 прекратилась около 10 лет назад. - person David Aldridge; 24.09.2015
comment
Дэвид, спасибо за такие мудрые и содержательные комментарии. Несомненно, вы внесли значительный вклад в обсуждение темы. Кстати, ссылка, которую вы предоставили несколько лет назад, в настоящее время фактически не работает. Спасибо. - person Nikolay Antipov; 26.09.2015
comment
Я критикую статью, а не вас. - person David Aldridge; 26.09.2015