简体   繁体   English

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

[英]Execution order of conditions in SQL 'where' clause

I have a set of conditions in my where clause like 我在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

Which of these conditions will be executed first? 首先执行以下哪些条件? I am using oracle. 我正在使用oracle。

Will I get these details in my execution plan? 我会在执行计划中获得这些细节吗? (I do not have the authority to do that in the db here, else I would have tried) (我没有权限在数据库中这样做,否则我会尝试)

Are you sure you "don't have the authority" to see an execution plan? 确定 “没有权力”来查看执行计划吗? What about using AUTOTRACE? 怎么用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")

As you can see, that gives quite a lot of detail about how the query will be executed. 如您所见,这提供了有关如何执行查询的大量详细信息。 It tells me that: 它告诉我:

  • the condition "emp.ename like 'K%'" will be applied first, on the full scan of EMP 条件“emp.ename like'K%'”将首先应用于EMP的全面扫描
  • then the matching DEPT records will be selected via the index on dept.deptno (via the NESTED LOOPS method) 那么匹配的DEPT记录将通过dept.deptno上的索引选择(通过NESTED LOOPS方法)
  • finally the filter "dept.loc like 'l%' will be applied. 最后将应用过滤器“dept.loc like'l%'。

This order of application has nothing to do with the way the predicates are ordered in the WHERE clause, as we can show with this re-ordered query: 这个应用程序顺序与谓词在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")

The database will decide what order to execute the conditions in. 数据库将决定执行条件的顺序。

Normally (but not always) it will use an index first where possible. 通常(但不总是)它会尽可能先使用索引。

As has been said, looking at the execution plan will give you some information. 如前所述,查看执行计划将为您提供一些信息。 However, unless you use the plan stability feature, you can't rely on the execution plan always remaining the same. 但是,除非您使用计划稳定性功能,否则您不能依赖执行计划始终保持不变。

In the case of the query you posted, it doesn't look like the order of evaluation will change the logic in any way, so I guess what you are thinking about is efficiency. 在您发布的查询的情况下,评估的顺序看起来不会以任何方式改变逻辑,因此我猜您正在考虑的是效率。 It's fairly likely that the Oracle optimizer will choose a plan that is efficient. Oracle优化器很可能会选择一个高效的计划。

There are tricks you can do to encourage a particular ordering if you want to compare the performance with base query. 如果要将性能与基本查询进行比较,可以使用一些技巧来鼓励特定的排序。 Say for instance that you wanted the timestamp condition to be executed first. 比如说您希望首先执行时间戳条件。 You could do this: 你可以这样做:

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'

The "materialize" hint should cause the optimizer to execute the inline query first, then scan that result set for the other conditions. “materialize”提示应该使优化器首先执行内联查询,然后扫描其他条件的结果集。

I'm not advising you do this as a general habit. 我并不建议你这样做是一般习惯。 In most cases just writing the simple query will lead to the best execution plans. 在大多数情况下,只需编写简单查询即可获得最佳执行计划。

To add to the other comments on execution plans, under the cpu-based costing model introduced in 9i and used by default in 10g+ Oracle will also make an assessment of which predicate evaluation order will result in lower computational cost even if that does not affect the table access order and method. 要添加到执行计划的其他注释,在9i中引入的基于cpu的成本计算模型,默认情况下在10g + Oracle中使用,还将评估哪个谓词评估顺序将导致较低的计算成本,即使这不会影响表访问顺序和方法。 If executing one predicate before another results in fewer predicates calculations being executed then that optimisaton can be applied. 如果在另一个谓词之前执行一个谓词导致执行的谓词计算更少,那么可以应用该优化。

See this article for more details: http://www.oracle.com/technology/pub/articles/lewis_cbo.html 有关更多详细信息,请参阅此文章: http//www.oracle.com/technology/pub/articles/lewis_cbo.html

Furthermore, Oracle doesn't even have to execute predicates where comparison with a check constraint or partition definitions indicates that no rows would be returned anyway. 此外,Oracle甚至不必执行谓词,其中与检查约束或分区定义的比较表明无论如何都不会返回任何行。

Complex stuff. 复杂的东西。

Finally, relational database theory says that you can never depend on the order of execution of the query clauses, so best not to try. 最后,关系数据库理论说你永远不能依赖查询子句的执行顺序,所以最好不要尝试。 As others have said, the cost-based optimizer tries to choose what it thinks is best, but even viewing explain plan won't guarantee the actual order that's used. 正如其他人所说,基于成本的优化器试图选择它认为最好的,但即使查看解释计划也不能保证所使用的实际订单。 Explain plan just tells you what the CBO recommends, but that's still not 100%. 解释计划只是告诉你CBO推荐的内容,但这仍然不是100%。

Maybe if you explain why you're trying to do this, some could suggest a plan? 也许如果你解释为什么要这样做,有人可能会建议一个计划?

Tricky question. 棘手的问题。 Just faced the same dilemma. 刚刚面临同样的困境。 I need to mention a function within a query. 我需要在查询中提到一个函数。 The function itself makes another query, so you understand how it affects performance in general. 函数本身会生成另一个查询,因此您可以了解它如何影响性能。 But in most cases we have, the function wouldn't be called so often if the rest of conditions executed first. 但是在大多数情况下,如果首先执行其余条件,则不会经常调用该函数。

Well, thought it would be useful to post here another article for topic. 嗯,认为在这里发表另一篇主题文章会很有用。

The following quote is copied from Donald Burleson 's site ( http://www.dba-oracle.com/t_where_clause.htm ) . 以下引用来自Donald Burleson的网站( http://www.dba-oracle.com/t_where_clause.htm )。

The ordered_predicates hint is specified in the Oracle WHERE clause of a query and is used to specify the order in which Boolean predicates should be evaluated. ordered_predicates提示在查询的Oracle WHERE子句中指定,用于指定应评估布尔谓词的顺序。

In the absence of ordered_predicates , Oracle uses the following steps to evaluate the order of SQL predicates: 缺少ordered_predicates情况下 ,Oracle使用以下步骤来评估SQL谓词的顺序:

  • Subqueries are evaluated before the outer Boolean conditions in the WHERE clause. 子查询在WHERE子句中的外部布尔条件之前计算。

  • All Boolean conditions without built-in functions or subqueries are evaluated in reverse from the order they are found in the WHERE clause, with the last predicate being evaluated first. 所有没有内置函数或子查询的布尔条件都按照它们在WHERE子句中找到的顺序进行反向计算,最后一个谓词首先被计算。

  • Boolean predicates with built-in functions of each predicate are evaluated in increasing order of their estimated evaluation costs. 具有每个谓词的内置函数的布尔谓词按其估计的评估成本的递增顺序进行评估。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM