Динамические подсказки в Oracle - PullRequest
0 голосов
/ 29 марта 2019

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

Я хотел бы сделать это:

PROCEDURE PROCESS_STEP_1 (p_cust_id NUMBER)
IS
  v_hint_value NUMBER;
BEGIN
  -- Select correct value from param table
  SELECT value INTO v_hint_value
    FROM param_table
    WHERE cust_id = p_cust_id
      AND process_name = 'PROCESS_STEP_1';

  INSERT INTO result_table  
  SELECT /*+ PARALLEL v_hint_value */ * FROM etc.

END;

Я знаю, чтоэто можно сделать с помощью динамических запросов.У нас их было много, и нам пришлось отказаться от них из-за плохой читабельности и других проблем (эти SQL довольно сложные).

У вас есть идеи, как можно реализовать что-то подобное?Спасибо!

1 Ответ

2 голосов
/ 29 марта 2019

ОК, я начну с полного отказа от этого подхода.Я пишу много высокопроизводительных приложений на SQL и очень редко использую подсказки.Тот факт, что вы, похоже, говорите о широко намекаемом приложении, где подсказки меняются в зависимости от установки, - это большой красный флаг.Я рекомендую вам попытаться удалить подсказки и решить, что может лежать в основе разработки приложений.

Тем не менее, Oracle имеет функцию перевода SQL.Он предназначен для того, чтобы позволить вам переводить SQL из приложений, написанных для баз данных не из Oracle, но он также может служить вашей цели.Что вы хотите сделать, так это использовать эту функцию для «перевода» подсказок в любом входящем операторе SQL до того, как Oracle его проанализирует.

Вот пример кода, иллюстрирующий эту концепцию и помогающий вам начать работу.Опять же - я не рекомендую это, но SO это место для ответов, а не лекций, так что вот оно ...

Шаг 1 - Убедитесь, что у вас есть права для этого

-- GRANT CREATE ANY SQL TRANSLATION PROFILE TO yourapplication
-- GRANT TRANSLATE ANY SQL TO yourapplication
-- GRANT USE ANY SQL TRANSLATION PROFLE TO yourapplication
-- GRANT EXECUTE ON SYS.DBMS_SQL_TRANSLATOR TO yourapplication

Создать таблицу для хранения переводов подсказок

Идея заключается в том, что вы встраиваете подсказки в свое приложение, например "/ + HINT12345 /, и что вы будете заполнять эту таблицу по-другому вкаждый клиентский сайт. Очевидно, вы можете получить более изощренный, чем этот.

CREATE TABLE myapp_hint_translations ( hint_id VARCHAR2(80), hint_text VARCHAR2(800) );

INSERT INTO myapp_hint_translations VALUES ( '/*+HINT12345*/','/*+PARALLEL(4)*/');

COMMIT;

Создание пакета PL / SQL для выполнения перевода подсказки

Вы должны использовать имена процедур и параметры, как указано.Они необходимы для пакета DBMS_SQL_TRANSLATOR, который мы будем использовать.

CREATE OR REPLACE PACKAGE myapp_hint_translator IS
  PROCEDURE translate_sql( sql_text IN CLOB, 
                           translated_text OUT CLOB );

  PROCEDURE translate_error( error_code IN BINARY_INTEGER,
                             translated_code OUT BINARY_INTEGER,
                             translated_sqlstate OUT VARCHAR2 );

END myapp_hint_translator;
/

CREATE OR REPLACE PACKAGE BODY myapp_hint_translator IS
  PROCEDURE translate_sql( sql_text IN CLOB, 
                           translated_text OUT CLOB ) IS
  BEGIN
    <<hint_search>>
    FOR r IN ( SELECT hint_id, hint_text FROM myapp_hint_translations ) LOOP
      IF INSTR(sql_text, r.hint_id ) > 0 THEN
        translated_text := replace(sql_text,r.hint_id,r.hint_text);
        RETURN;
      END IF;
    END LOOP;
    -- No translation made
    translated_text := sql_text;
  END translate_sql;

  PROCEDURE translate_error( error_code IN BINARY_INTEGER,
                             translated_code OUT BINARY_INTEGER,
                             translated_sqlstate OUT VARCHAR2 ) IS
  BEGIN
    -- We are not using this feature
    NULL;
  END;

END myapp_hint_translator;

Скажите Oracle, чтобы начать использовать наш переводчик

BEGIN
  dbms_sql_translator.create_profile(profile_name => 'MYAPP');
  dbms_sql_translator.set_attribute(profile_name => 'MYAPP',
                                    attribute_name => dbms_sql_translator.attr_translator,
                                    attribute_value => 'myappschema.myapp_hint_translator');
END;

ALTER SESSION SET SQL_TRANSLATION_PROFILE=MYAPP;

ALTER SESSION SET EVENTS = '10601 trace name context forever, level 32';

-- Test some of your application and verify hints are being translated
...