У меня есть таблица A
с интервалами (COL1, COL2)
:
CREATE TABLE A (
COL1 NUMBER(15) NOT NULL,
COL2 NUMBER(15) NOT NULL,
VAL1 ...,
VAL2 ...
);
ALTER TABLE A ADD CONSTRAINT COL1_BEFORE_COL2 CHECK (COL1 <= COL2);
Интервалы гарантируются как "исключительные", т.е. они никогда не будут перекрываться. Другими словами, этот запрос не дает строк:
SELECT *
FROM (
SELECT
LEAD(COL1, 1) OVER (ORDER BY COL1) NEXT,
COL2
FROM A
)
WHERE COL2 >= NEXT;
В настоящее время существует индекс на (COL1, COL2)
. Теперь мой запрос следующий:
SELECT /*+FIRST_ROWS(1)*/ *
FROM A
WHERE :some_value BETWEEN COL1 AND COL2
AND ROWNUM = 1
Это выполняется хорошо (менее миллисекунд для миллионов записей в A
) для низких значений :some_value
, потому что они очень избирательны по индексу. Но он работает довольно плохо (почти секунда) для больших значений :some_value
из-за более низкой селективности предиката доступа.
План исполнения кажется мне хорошим. Поскольку существующий индекс уже полностью охватывает предикат, я получаю ожидаемый INDEX RANGE SCAN
:
------------------------------------------------------
| Id | Operation | Name | E-Rows |
------------------------------------------------------
| 0 | SELECT STATEMENT | | |
|* 1 | COUNT STOPKEY | | |
| 2 | TABLE ACCESS BY INDEX ROWID| A | 1 |
|* 3 | INDEX RANGE SCAN | A_PK | |
------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM=1)
3 - access("VAL2">=:some_value AND "VAL1"<=:some_value)
filter("VAL2">=:some_value)
В 3
становится очевидным, что предикат доступа является выборочным только для низких значений :some_value
, тогда как для более высоких значений операция фильтра "пинает" по индексу.
Есть ли способ улучшить этот запрос, чтобы быть быстрым, независимо от значения :some_value
? Я могу полностью переделать таблицу, если необходима дальнейшая нормализация.