2012-02-10 47 views
1

this question的啓發我決定測試rank()函數,試圖查看子查詢的效率是否低於rank。所以,我創建了一個表:性能: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; 
/

然後測試了兩種querys:

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()

正如你所看到的,子查詢的成本比排名較低的()。這是正確的嗎?我在那裏錯過了什麼?

PS:測試表中還有一個完整的查詢和低成本的仍然子查詢。

EDIT

我生成的兩個查詢的的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 

我可以斷定,子查詢不將總是比等級低效率?何時顯示排名而不是子查詢?

+0

您是否分析了表格和索引? – 2012-02-10 19:22:44

+0

(不知道這是否有效或違反了某些規則,但..) @Justin Cave,因爲這個任務與你在其他帖子中的回答有關,你能否請你看看並提出你的意見? – 2012-02-10 20:01:29

回答

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; 
+0

在我提到的問題中,其中一個答案說'sub query'比'rank()'效率低。我試圖證實這一點。 – 2012-02-10 18:53:36

+2

@SérgioMichels:我想說你的測試證明了rank()方法並不總是比子查詢方法更高效。這兩種方法都是用於獲得理想結果的合理技術,哪一種效率更高取決於多種因素,例如涉及哪些列,如何對它們進行索引,數據大小和分佈。在你的情況下,子查詢是非常有效的,因爲它能夠精確地使用索引覆蓋的列,並利用索引條目的排序來避免額外的排序。在其他情況下,這不是事實。 – 2012-02-10 21:08:22

2

成本是基於成本的優化器對執行查詢所需花費的估計。

CBO可能會弄錯它,特別是如果統計數據過期。

那麼,該怎麼辦?嘗試使用'set autotrace on'執行每個查詢。每個查詢有多少個緩衝區獲取和物理讀取?換句話說,每個查詢都有多少實際的工作?

希望有所幫助。

+0

當然,在查看物理讀取時,緩存可能會發揮作用。 – 2012-02-10 18:38:22

+0

@DaveCosta如何避免查詢的緩存? – 2012-02-10 18:42:05

+0

@Mark J. Bobak謝謝你的回答,我用tkprof的結果更新了我的問題,並試圖更好地解釋這個問題。你能否看看是否有新的東西添加到答案中?再次感謝:) – 2012-02-10 20:02:59