我有一个前 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;
此查询运行良好。它可以非常有效地为我找到海量数据集的前 10 行,使用关于 Mercer_id、subscription_status、transaction_date 的索引。
-------------------------------------------------------------------------------------------------------
| 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,这是正确的。
现在,我需要获取一组商家 ID 的前 N 条记录,因此如果我将查询更改为包含两个商家 ID,则性能坦克:
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 行来自两次索引范围扫描——当索引范围扫描达到 10 行时,Oracle 不再中止索引范围扫描。我认为会发生的是,Oracle 最多会为每个 Mercer_id 获取 10 行,因为知道查询最多将返回 10 行。然后它会根据交易日期对 10 + 10 行进行排序并输出前 10 行,但它拒绝这样做。
当我需要将商家列表传递到查询中时,有谁知道如何获得第一个查询的性能?我可能可以使用 union all 获得性能,但商家列表是可变的,可能介于 1 或 2 到几百个之间。