Oracle

為什麼對 max() 查詢進行索引範圍掃描?

  • March 16, 2021

我有一個記錄數據傳輸到另一個系統的表。

create table transfer_log (id number(10),
                          fk_data number(10),
                          first_sent_time date,
                          last_sent_time date,
                          transfer_status number(3),
                          error_message varchar2(250));

create unique index pk_transfer_log on transfer_log (id);
alter table transfer_log add constraint pk_transfer_log primary key (id);

create index idx_transfer_log_status on transfer_log (transfer_status, last_sent_time desc);

transfer_status 列儲存來自發送數據的 HTTP 狀態。transfer_status 永遠不會為空(最初為 0),last_sent_time 最初為空。所以我進行了一次健康檢查,看看上次成功傳輸的時間是:

select
 max(d.last_sent_time)
from
 transfer_log d
where
 d.transfer_status = 200
;

我希望索引能讓這個查詢更快。但現在已經接近 1 秒,執行計劃看起來不太好:

----------------------------------------------------------------------------------------
| Id | Operation           | Name                    | Rows    | Bytes   | Cost | Time |
----------------------------------------------------------------------------------------
|  0 | SELECT STATEMENT    |                         |       1 |       6 | 2624 |      |
|  1 |   SORT AGGREGATE    |                         |       1 |       6 |      |      |
|  2 |    INDEX RANGE SCAN | IDX_TRANSFER_LOG_STATUS | 1272670 | 7636020 | 2624 |      |
----------------------------------------------------------------------------------------

我希望索引(尤其是使用遞減的 last_sent_time)可以使這個查詢更快,因為只需要讀取第一個條目。

我做錯什麼了?

刪除該索引並在沒有 desc 的情況下創建:

create index idx_transfer_log_status on transfer_log (transfer_status, last_sent_time);

數據庫可以決定以降序讀取升序索引。最後一個條目的讀取速度與第一個條目一樣快。

但更好的是,當您搜尋 MIN/MAX 值並使用該操作時,它可以辨識一個案例:

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  6q8sbnqkajz74, child number 1
-------------------------------------
select   max(d.last_sent_time) from   transfer_log d where
d.transfer_status = 200

Plan hash value: 3076158531

--------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                    | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                         |       |       |     2 (100)|          |
|   1 |  SORT AGGREGATE              |                         |     1 |    11 |            |          |
|   2 |   FIRST ROW                  |                         |     1 |    11 |     2   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN (MIN/MAX)| IDX_TRANSFER_LOG_STATUS |     1 |    11 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------

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

 3 - access("D"."TRANSFER_STATUS"=200)

不幸的是,這不適用於desc索引。

引用自:https://dba.stackexchange.com/questions/287130