Порядок выполнения условий в предложении 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

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

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

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 (через вложенные циклы метод)
  • наконец, фильтр " 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")

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

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


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

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

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

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'

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

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


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

смотрите статью подробности: http://www.oracle.com/technology/pub/articles/lewis_cbo.html

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

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


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

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


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

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

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

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

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

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

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

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