sql where子句中的列顺序

时间:2013-01-23 07:49:45

标签: sql performance oracle query-optimization

所有

  1. sql where子句中的列顺序是否有效?我在网上搜索,然后发现一些建议,首先说的是加入然后是其他过滤器。 例如,

    select t1.a, t2.b 
    from table1 t1, table2 t2 
    where t1.a = t2.a and t1 > 1 and t2 > 2;
    
  2. 如果我将t1 > 1更改为t1.a = t2.a的前面,

    是否有任何问题?

    1. 我想知道exists子句中的列顺序。 例如,

      select t1.a, t2.b 
      from table1, table2 t2 
      where t1.a = t2.a 
        and not exists (select 1 from table3 t3 where t1.a = t3.a and t1.b = t3.b)
      
    2. 如果我将t1.b = t3.b更改为t3.b = t1.b,会有什么影响吗? 列顺序是否至关重要?

      1. 任何人都可以解释一下sql select执行步骤,并给出一些有用的教程链接吗?

4 个答案:

答案 0 :(得分:2)

要解决此问题,请使用JOIN关键字来使用显式ANSI SQL-92语法:

select t1.a, t2.b 
from table1 t1
inner join table2 t2 on t1.a = t2.a
where  t1 > 1 and t2 > 2;

这样,您将不再具有WHERE子句中的连接条件,并且可以轻松添加更多条件。

对于第二个查询,您可以使用OUTER JOIN

select t1.a, t2.b 
from table1
inner join table2 t2 on t1.a = t2.a
LEFT JOIN table3 t3 on t1.a = t3.a and t1.b = t3.b
where t3.a IS NULL;

我知道这不是回答你的问题,但是这个旧的连接语法是在where子句的条件中这一切都模糊不清的问题。不推荐,所以尽量避免它:

答案 1 :(得分:2)

人们说WHERE子句中的谓词顺序不会影响性能,大多数时候都是 。然而,我们经常知道我们系统中的数据,特别是它的分布和偏差,而不是优化器可以从其统计数据中得出的数据。在这种情况下,我们必须为优化程序提供最佳信息。

这是一个从我上周遇到的现实生活情况中抽象出来的一个例子(我现在还没有时间来测试一个测试用例,但我会在以后)。

情况:三张桌子,父母和两个孩子。任务是通过查找其子项中的非唯一行来选择父项中的唯一行。所有表都有数百万行。

我的第一次尝试是这样的:

select parent.*
from   child1
       , child2
       , parent
where child1.col_a = 'whatever'
and child2.col_n = 9999
and child1.parent_id = child2.parent_id
and parent.id = child2.parent_id

查询返回了正确的结果集,但性能非常差。解释计划显示查询驱逐了CHILD2。这是错误的,因为CHILD1上的过滤器更具选择性。所以我重写了这样的查询:

select parent.*
from   child1
       , child2
       , parent
where child1.col_a = 'whatever'
and child2.col_n = 9999
and child2.parent_id = child1.parent_id
and parent.id = child1.parent_id

现在,查询驱逐了CHILD1,性能提升了一个数量级以上。这不会一直发生,但我说摆弄WHERE子句仍然是一种有效的调整技术。

CBO是一款非常智能的软件。尽管如此,我们不能只是在它上面抛出一个贪婪的WHERE条款,并期望它每次都能产生最好的解释计划。查询越复杂(其中复杂性由连接数定义),我们以有意义的方式组织WHERE子句就越重要。它没有任何伤害,它可能只是做一些好事。


顺便说一句,那些说ANSI连接语法不会再次影响性能的人只是大部分时间。偶尔它会导致优化器产生较差的执行计划。 Find out more

答案 2 :(得分:0)

在基于成本的优化器(CBO)下的where子句中谓词的排序并不重要,因为CBO会很乐意重新安排谓词,因为它看起来合适(除非你在那里暗示告诉oracle不这样做)。

基于规则的优化器确实应该注意谓词的排序,但希望你不会使用仍然使用RBO的旧版Oracle。

答案 3 :(得分:0)

where子句中的顺序并不重要。 ANSI JOIN语法提高了可读性,但不会影响性能。为了证明这一点:

create table t1 (a number, x number);
create table t2 (a number, b number);
insert into t1 (a, x) select level, mod(level,100) from dual connect by level <= 100000;
insert into t2 (a, b) select level, mod(level,10)  from dual connect by level <= 100000;
exec dbms_stats.gather_table_stats(user,'t1');
exec dbms_stats.gather_table_stats(user,'t2');
set autotrace trace explain

所有四个查询

select t1.a, t2.b from t1, t2 where t1.a=t2.b and t1.x > 5 and t2.b > 5;
select t1.a, t2.b from t1, t2 where t1.a=t2.b and t2.b > 5 and t1.x > 5;
select t1.a, t2.b from t1, t2 where t1.x > 5 and t2.b > 5 and t1.a=t2.b;
select t1.a, t2.b from t1 join t2 on t1.a=t2.b where t1.x > 5 and t2.b > 5;

生成完全相同的查询计划

Plan hash value: 282751716
---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      | 44444 |   434K|    88   (7)| 00:00:02 |
|*  1 |  HASH JOIN         |      | 44444 |   434K|    88   (7)| 00:00:02 |
|*  2 |   TABLE ACCESS FULL| T2   | 44444 |   130K|    42   (5)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| T1   | 94946 |   649K|    44   (5)| 00:00:01 |
---------------------------------------------------------------------------

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

   1 - access("T1"."A"="T2"."B")
   2 - filter("T2"."B">5)
   3 - filter("T1"."X">5 AND "T1"."A">5)