Перекрестная ссылка на функциональный индекс в Oracle - PullRequest
3 голосов
/ 31 января 2011

У меня есть две таблицы, подобные этой

   create table A_DUMMY (
        TRADE_ID     VARCHAR2(16)
        TRADE_DATA   VARCHAR2(500)
   )

   create table B_DUMMY (
        EXT_TRADE_ID VARCHAR2(16)
        EXT_DATA     VARCHAR2(250)
   )

И есть представление, что построить что-то вроде этого

   CREATE OR REPLACE VIEW DUMMY_VIEW("TRADE_DATA", "EXT_DATA")
   AS
   SELECT A.TRADE_DATA, B.EXT_DATA FROM A_DUMMY A, B_DUMMY B 
   WHERE 
          GET_TRADE_NUMBER(A.TRADE_ID,'-') = GET_TRADE_NUMBER(B.EXT_TRADE_ID,'_') 
        OR
          GET_TRADE_NUMBER(A.TRADE_ID,'-') = B.EXT_TRADE_ID

Чтобы оптимизировать это, я создал функциональный индекс для TRADE_ID в A_DUMMY и EXT_TRADE_ID в B_DUMMY.

Функция выглядит так:

   create or replace function 
      GET_TRADE_NUMBER(trade in varchar2, separator in varchar2) 
   return varchar2
     deterministic
   as
   begin    
        return SUBSTR(trade, 0, INSTR(trade, separator, 1, 1) - 1);
   end;

Функциональные индексы выглядят так

   create index A_DUMMY_IDX ON A_DUMMY(GET_TRADE_NUMBER(TRADE_ID,'-'));
   create index B_DUMMY_IDX ON B_DUMMY(GET_TRADE_NUMBER(EXT_TRADE_ID,'_'));

Данные выглядят так:

   INSERT INTO a_dummy VALUES ('7874-LND', 'item1');
   INSERT INTO a_dummy VALUES ('7845-NY', 'item2'); 
   INSERT INTO a_dummy VALUES ('7844-NY', 'item3');

   INSERT INTO b_dummy VALUES ('7844', 'item4');
   INSERT INTO b_dummy VALUES ('7845_LND', 'item5');
   INSERT INTO b_dummy VALUES ('7874_LND', 'item5'); 

Как я могу заставить Oracle использовать эти индексы в предоставленном запросе для DUMMY_VIEW?

Потому что, похоже, что бы я ни делал в соответствии с планом объяснения, Оракул их игнорирует.

1 Ответ

4 голосов
/ 31 января 2011

без примеров данных и подробностей функции трудно определить, почему Oracle не использует ваши индексы на основе функций.

Я продемонстрирую пример использования индекса:

/* Setup */
CREATE OR REPLACE FUNCTION fnc (trade_id VARCHAR2) 
   RETURN VARCHAR2 
   DETERMINISTIC IS
BEGIN
   RETURN LOWER(trade_id);
END fnc;
/

INSERT INTO a_dummy VALUES ('a', 'item1');
INSERT INTO a_dummy VALUES ('A', 'item2');
INSERT INTO a_dummy VALUES ('b', 'item3');

INSERT INTO b_dummy VALUES ('a', 'item4');
INSERT INTO b_dummy VALUES ('B', 'item5');
INSERT INTO b_dummy VALUES ('C', 'item5');

При этой настройке мы замечаем, что индекс используется с простыми запросами:

SQL> SELECT A.TRADE_DATA, B.EXT_DATA
  2    FROM A_DUMMY A, B_DUMMY B
  3   WHERE fnc(A.TRADE_ID) = B.EXT_TRADE_ID;    

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=8 Card=3 Bytes=1197)
   1    0   NESTED LOOPS (Cost=8 Card=3 Bytes=1197)
   2    1     TABLE ACCESS (FULL) OF 'B_DUMMY' (TABLE) (Cost=5 Card=3 Bytes=411)
   3    1     TABLE ACCESS (BY INDEX ROWID) OF 'A_DUMMY' (TABLE) (Cost=1 [...]
   4    3       INDEX (RANGE SCAN) OF 'A_DUMMY_IDX' (INDEX) (Cost=0 Card=1)

.. но, к сожалению, не с вашим примером запроса. Оператор OR может помешать оптимизатору использовать индексы. Я предлагаю вам использовать эквивалентный запрос:

SQL> SELECT A.TRADE_DATA, B.EXT_DATA
  2    FROM A_DUMMY A, B_DUMMY B
  3   WHERE fnc(A.TRADE_ID) = fnc(B.EXT_TRADE_ID)
  4  UNION ALL
  5  SELECT A.TRADE_DATA, B.EXT_DATA
  6    FROM A_DUMMY A, B_DUMMY B
  7   WHERE fnc(A.TRADE_ID) = B.EXT_TRADE_ID
  8     AND fnc(A.TRADE_ID) != fnc(B.EXT_TRADE_ID);

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=16 Card=5 Bytes=1995)
   1    0   UNION-ALL
   2    1     NESTED LOOPS (Cost=8 Card=3 Bytes=1197)
   3    2       TABLE ACCESS (FULL) OF 'A_DUMMY' (TABLE) (Cost=5 Card=3 Byt[...]
   4    2       TABLE ACCESS (BY INDEX ROWID) OF 'B_DUMMY' (TABLE) (Cost=1 [...]
   5    4         INDEX (RANGE SCAN) OF 'B_DUMMY_IDX' (INDEX) (Cost=0 Card=1)
   6    1     NESTED LOOPS (Cost=8 Card=2 Bytes=798)
   7    6       TABLE ACCESS (FULL) OF 'B_DUMMY' (TABLE) (Cost=5 Card=3 Byt[...]
   8    6       TABLE ACCESS (BY INDEX ROWID) OF 'A_DUMMY' (TABLE) (Cost=1 [...]
   9    8         INDEX (RANGE SCAN) OF 'A_DUMMY_IDX' (INDEX) (Cost=0 Card=1)

В качестве примечания: вы объединяете две таблицы Без фильтра соединение HASH без индекса, возможно, является самым быстрым способом вычисления соединения. Полное сканирование не всегда зло, индексы не всегда хорошо .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...