SQL'where'子句中条件的执行顺序

sar*_*ego 14 sql oracle 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
Run Code Online (Sandbox Code Playgroud)

首先执行以下哪些条件?我正在使用oracle.

我会在执行计划中获得这些细节吗?(我没有权限在数据库中这样做,否则我会尝试)

Ton*_*ews 20

确定 "没有权力"来查看执行计划吗?怎么用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")
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这提供了有关如何执行查询的大量详细信息.它告诉我:

  • 条件"emp.ename like'K%'"将首先应用于EMP的全面扫描
  • 那么匹配的DEPT记录将通过dept.deptno上的索引选择(通过NESTED LOOPS方法)
  • 最后将应用过滤器"dept.loc like'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")
Run Code Online (Sandbox Code Playgroud)


Gre*_*reg 7

数据库将决定执行条件的顺序.

通常(但不总是)它会尽可能先使用索引.

  • 当它们更好时,它更喜欢它们:)根据我的经验,这是“正常”的 (2认同)

Dav*_*sta 6

如前所述,查看执行计划将为您提供一些信息.但是,除非您使用计划稳定性功能,否则您不能依赖执行计划始终保持不变.

在您发布的查询的情况下,评估的顺序看起来不会以任何方式改变逻辑,因此我猜您正在考虑的是效率.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'
Run Code Online (Sandbox Code Playgroud)

"materialize"提示应该使优化器首先执行内联查询,然后扫描其他条件的结果集.

我并不建议你这样做是一般习惯.在大多数情况下,只需编写简单查询即可获得最佳执行计划.