性能:rank()vs子查询。子查询成本较低?

时间:2012-02-10 17:57:35

标签: performance oracle subquery rank

this question的启发我决定测试rank()函数,试图查看子查询的效率是否低于排名。所以我创建了一个表:

create table teste_rank ( codigo number(7), data_mov date, valor number(14,2) );
alter table teste_rank add constraint tst_rnk_pk primary key ( codigo, data_mov );

并插入一些记录......

declare
  vdata date;
begin
  dbms_random.initialize(120401);
  vdata := to_date('04011997','DDMMYYYY');
  for reg in 1 .. 465 loop
    vdata := to_date('04011997','DDMMYYYY');
    while vdata <= trunc(sysdate) loop
      insert into teste_rank 
          (codigo, data_mov, valor) 
        values 
          (reg, vdata, dbms_random.value(1,150000));
      vdata := vdata + 2;
    end loop;
    commit;
  end loop;
end;
/

然后测试了两个查询:

select * 
  from teste_rank r
 where r.data_mov = ( select max(data_mov) 
                        from teste_rank 
                       where data_mov <= trunc(sysdate) 
                         and codigo = 1 )
   and r.codigo = 1;

Explain Plan for sub query


select *
  from ( select rank() over ( partition by codigo order by data_mov desc ) rn, t.*
           from teste_rank t
          where codigo = 1
            and data_mov <= trunc(sysdate) ) r
 where r.rn = 1;

Explain plan rank()

如您所见,子查询的成本低于rank()。这是正确的吗?我错过了什么吗?

PS:在表格中使用完整查询进行测试,但仍以低成本进行子查询。

修改

我生成了两个查询的tkprof(跟踪一个,关闭数据库,启动并追踪第二个)。

对于子查询

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.02          3          5          0           0
Execute      1      0.00       0.00          0          3          0           0
Fetch        2      0.00       0.00          1          4          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.00       0.02          4         12          0           1

rank()

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.02          3          3          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.00       0.00          9         19          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.01       0.03         12         22          0           1

我能否断定子查询的效率总是低于排名?何时表示排名而不是子查询?

2 个答案:

答案 0 :(得分:2)

成本是基于成本的优化程序对执行查询所需内容的估计。

CBO可能会弄错,特别是如果统计数据已经过时。

那么,该怎么办?尝试使用'set autotrace on'执行每个查询。每个查询执行多少缓冲区获取和物理读取?换句话说,每个查询执行了多少实际工作?

希望有所帮助。

答案 1 :(得分:2)

我不确定你的问题是什么。是的,根据这两个执行计划,在这种情况下,子查询方法具有较低的预期成本。似乎并不太令人惊讶,因为它可以使用索引非常快速地找到您感兴趣的确切行。特别是在这种情况下,子查询只需要快速扫描PK索引。如果子查询涉及不属于索引的列,则情况可能会有所不同。

使用rank()的查询必须获取所有匹配的行并对其进行排名。我不相信优化器有任何短路逻辑来识别这是一个前n个查询,因此避免完全排序,即使你真正关心的是排名第一的行。

您也可以尝试使用此格式,优化程序应将其识别为前n个查询。在您的情况下,我希望它只需要对索引进行单个范围扫描,然后进行表访问。

select * 
  from (select *
          from teste_rank r
          where data_mov <= trunc(sysdate) 
            and codigo = 1
        order by data_mov desc)
  where rownum=1;