Я изучаю, можно ли использовать динамические подсказки в 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 довольно сложны).
У вас есть идеи, как что-то подобное можно реализовать? Спасибо!





Хорошо, я начну с полного отрицания этого подхода. Я пишу много высокопроизводительных SQL-приложений и очень редко использую подсказки. Тот факт, что вы, кажется, говорите о приложении с массовыми подсказками, где подсказки различаются в зависимости от установки, является большим красным флагом. Я рекомендую вам попытаться удалить подсказки и решить, что может лежать в основе проблем дизайна приложения.
Тем не менее, у Oracle есть функция перевода SQL. Он предназначен для того, чтобы вы могли переводить SQL-запросы из приложений, написанных для баз данных, отличных от Oracle, но он также может служить вашей цели. Что вы хотите сделать, так это использовать эту функцию для «перевода» подсказок в любом входящем операторе SQL до того, как Oracle его проанализирует.
Вот пример кода, чтобы проиллюстрировать концепцию и начать работу. Опять же - я не рекомендую это, но SO - это место для ответов, а не лекций, так что вот оно...
-- 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
Идея здесь заключается в том, что вы встраиваете подсказки в свое приложение, например «/+ ПОДСКАЗКА12345/», и что вы будете заполнять эту таблицу по-разному на каждом сайте клиента. Очевидно, что вы можете сделать что-то более сложное.
CREATE TABLE myapp_hint_translations ( hint_id VARCHAR2(80), hint_text VARCHAR2(800) );
INSERT INTO myapp_hint_translations VALUES ( '/*+HINT12345*/','/*+PARALLEL(4)*/');
COMMIT;
Вы должны использовать имена процедур и параметры как указано. Они требуются
пакет 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;
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
Если вы можете исправить это с помощью подсказки, вы можете исправить это с помощью варианта того, что я опубликовал. Возможно, вам придется каким-то образом удалить SQL-запросы из библиотечного кеша, чтобы заставить их повторно анализировать. Опять же, вся эта идея звучит плохо для меня.
Существует множество настроек уровня базы данных и уровня сеанса для контроля или ограничения степени параллелизма (DOP) или «автоматической» степени для указания Oracle вычислить наилучший DOP. Те не работают? Возможно, вы захотите опубликовать отдельный вопрос конкретно о динамической настройке DOP для ваших запросов, поскольку он сильно отличается от вашего сообщения о динамическом изменении подсказок.
спасибо за информативный пост, я не знал об этой функции! Но боюсь, что мне это не поможет - по крайней мере, я не знаю, как динамически менять заполнитель на подсказку, так как при каждом выполнении процедуры он может быть разным. Я обновил сообщение, чтобы лучше проиллюстрировать мой вариант использования. Это не сильно намекающее приложение, мы просто хотим лучше контролировать параллелизм — теперь у нас есть фиксированные степени, но наши администраторы баз данных сказали нам, что для разных обрабатываемых клиентов разные значения приведут к лучшей производительности из-за больших различий в объеме данных.