Нужен индекс с функцией sys_connect_by_path? Как подражать этому? - PullRequest
1 голос
/ 09 марта 2010

У меня есть таблица с самообращением в Oracle 9i и представление, которое получает данные из нее:

CREATE OR REPLACE VIEW config AS
SELECT c.node_id,
       c.parent_node_id,
       c.config_key,
       c.config_value,
       (SELECT c2.config_key 
          FROM vera.config_tab c2 
         WHERE c2.node_id = c.parent_node_id) AS parent_config_key,
       sys_connect_by_path(config_key, '.') path,
       sys_connect_by_path(config_key, '->') php_notation
  FROM config_tab c
CONNECT BY c.parent_node_id = PRIOR c.node_id
 START WITH c.parent_node_id IS NULL
 ORDER BY LEVEL DESC

В таблице хранится конфигурация для приложения PHP. Теперь мне нужно использовать тот же конфиг в представлении оракула.

Я хотел бы выбрать некоторые значения в представлении по пути, но, к сожалению, это занимает 0,15 с, поэтому это недопустимая стоимость.

SELECT * FROM some_table
 WHERE some_column IN (
   SELECT config_value FROM config_tab WHERE path = 'a.path.to.config'
 )

Сначала я подумал об индексе функции в sys_connect_by_path, но это невозможно, так как для этого требуется также предложение CONNECT BY.

Есть предложения, как мне эмулировать индекс в столбце пути из представления "config"?

1 Ответ

2 голосов
/ 09 марта 2010

Если ваши данные не часто меняются в config_tab, вы можете использовать материализованное представление с тем же запросом, что и ваше представление. Затем вы можете индексировать столбец path вашего материализованного представления.

CREATE MATERIALIZED VIEW config
   REFRESH COMPLETE ON DEMAND 
   AS <your_query>;

CREATE INDEX ix_config_path ON config (path);

Поскольку это сложный запрос, вам потребуется полное обновление вашего материализованного представления каждый раз, когда обновляется базовая таблица, чтобы данные в MV не устаревали.

Обновление

  • Ваш столбец path будет определен как VARCHAR2(4000). Вы можете ограничить размер этого столбца, чтобы проиндексировать его. В вашем запросе замените, например, sys_connect_by_path(...) на SUBSTR(sys_connect_by_path(..., 1, 1000).
  • Вы не сможете использовать REFRESH ON COMMIT для сложного MV. Простой триггер не сработает. Вам нужно будет изменить код, который обновляет вашу базовую таблицу, чтобы как-то включить обновление, я не знаю, практично ли это в вашей среде.
  • Вы также можете использовать триггер, который отправляет задание, которое обновит MV. Задание будет выполнено после фиксации (это функция dbms_job). Это более сложно, так как вам придется проверять, что вы запускаете задание только один раз за транзакцию (например, с помощью переменной пакета). Опять же, это практично, если вы не часто обновляете базовую таблицу.
...