2012-07-27 39 views
2

我有一個前N個查詢會給我帶來問題。訪問ID列表時前N個查詢性能

首先,我有如下所示的查詢:

select /*+ gather_plan_statistics */ * from 
(
    select rowid 
    from payer_subscription ps 
    where ps.subscription_status = :i_subscription_status 
    and ps.merchant_id   = :merchant_id2 
    order by transaction_date desc 
) where rownum <= :i_rowcount; 

此查詢效果很好。通過使用merchant_id,subscription_status,transaction_date上的索引,它可以非常有效地找到大數據集的前10行。

------------------------------------------------------------------------------------------------------- 
| Id | Operation      | Name  | Starts | E-Rows | A-Rows | A-Time | Buffers | 
------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |    |  1 |  |  10 |00:00:00.01 |  4 | 
|* 1 | COUNT STOPKEY    |    |  1 |  |  10 |00:00:00.01 |  4 | 
| 2 | VIEW      |    |  1 |  11 |  10 |00:00:00.01 |  4 | 
|* 3 | INDEX RANGE SCAN DESCENDING| SODTEST2_IX |  1 | 100 |  10 |00:00:00.01 |  4 | 
------------------------------------------------------------------------------------------------------- 

正如您所見,每個階段估計的實際行數是10,這是正確的。

現在,我有一個要求,以獲得前N個記錄集merchant_Ids的,所以如果我更改查詢包括兩個merchant_ids,性能坦克:

select /*+ gather_plan_statistics */ * from 
(
    select rowid 
    from payer_subscription ps 
    where ps.subscription_status = :i_subscription_status 
     and (ps.merchant_id = :merchant_id or 
      ps.merchant_id = :merchant_id2) 
    order by transaction_date desc 
) where rownum <= :i_rowcount; 

    ---------------------------------------------------------------------------------------------------------------------------- 
| Id | Operation    | Name  | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem | 
---------------------------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT  |    |  1 |  |  10 |00:00:00.17 |  178 |  |  |   | 
|* 1 | COUNT STOPKEY   |    |  1 |  |  10 |00:00:00.17 |  178 |  |  |   | 
| 2 | VIEW     |    |  1 | 200 |  10 |00:00:00.17 |  178 |  |  |   | 
|* 3 | SORT ORDER BY STOPKEY|    |  1 | 200 |  10 |00:00:00.17 |  178 | 2048 | 2048 | 2048 (0)| 
| 4 |  INLIST ITERATOR  |    |  1 |  | 42385 |00:00:00.10 |  178 |  |  |   | 
|* 5 |  INDEX RANGE SCAN | SODTEST2_IX |  2 | 200 | 42385 |00:00:00.06 |  178 |  |  |   | 
---------------------------------------------------------------------------------------------------------------------------- 

注意,現在有42K來自兩個索引範圍掃描的行 - Oracle在達到10行時不再放棄索引範圍掃描。我認爲會發生的事情是,Oracle會爲每個merchant_id獲取至多10行,因爲知道最多10行將被查詢返回。然後它會根據交易日期對10 + 10行進行排序並輸出前10,但拒絕這樣做。

有沒有人知道如何獲得第一個查詢的性能,當我需要將商家列表傳遞到查詢中時?我大概可以使用union來獲得性能,但商家列表是可變的,可以是1或2到100之間的任意值。

回答

1

您可以使用--+ use_concat提示使Oracle執行查詢,就好像它是一個UNION ALL。

documentation

的USE_CONCAT提示指示優化器使用所有設置操作者UNION變換組合的查詢的WHERE子句中 OR條件成複合查詢 。如果沒有此提示,則僅在使用 級聯的查詢的成本比沒有它們的成本便宜時纔會發生此轉換。 USE_CONCAT 提示覆蓋了成本考慮因素。

+0

有趣。我一直在試圖改變這個計劃,但沒有任何影響。我聽起來像是一個潛在的選擇,如果我能夠實現它的話! – 2012-07-27 14:59:03

+0

您是否嘗試在內部查詢中使用它? – jva 2012-07-27 15:01:43

+0

是的,我在內外兩部分都試過了。 – 2012-07-27 15:07:55

0

我不知道這會有所幫助,但你CAH嘗試在更換或運營商:

and ps.merchant_id IN (:merchant_id, :merchant_id2) 
+0

查詢計劃與IN完全相同或使用OR。 – 2012-07-27 14:31:43

1

有很多情況下use_concat被忽略。 請參閱:MOS注意:不同版本的USE_CONCAT提示(文檔ID 259741.1)

我已在10.2.0.4,11.2.0.1中使用OR_EXPAND取得了成功,其中USE_CONCAT不起作用。 /* + OR_EXPAND(化名列名)*/

這裏記載: http://www.hellodba.com/reader.php?ID=199&lang=EN