Коллеги, всем привет! 👋
На связи Денис.
Копался тут, как Oracle считает SQL_ID, и по ходу пьесы наткнулся на интересный пакет - DBMS_SQL_TRANSLATOR (есть с 12c). Кстати, в нём есть функция SQL_ID - про неё в следующем посте. А сам пакет умеет на лету подменять текст запроса: приложение шлёт одно, а база выполняет другое.
Честно скажу: в своей практике я ни разу не видел, чтобы его использовали. Если кто-то применял на проде - поделитесь в комментах, очень интересно 🙏
По мне, это тёмная магия Oracle 🧙♂️ Знает про неё узкий круг специалистов, а используют её очень редко. Сделаете на ней что-то - коллеги просто не поймут, что происходит, и запутаются: в коде один запрос, а в базе выполняется другой.
Как это работает
Создаём профиль трансляции, регистрируем пару «исходный SQL -> SQL на замену» и включаем профиль в сессии.
begin
dbms_sql_translator.create_profile('APP_FIX');
-- переводить и обычный оракловый SQL, а не только "чужой"
dbms_sql_translator.set_attribute('APP_FIX',
dbms_sql_translator.attr_foreign_sql_syntax,
dbms_sql_translator.attr_value_false);
dbms_sql_translator.register_sql_translation('APP_FIX',
'select count(*) from orders where status = :b1',
'select /*+ full(o) */ count(*) from orders o where status = :b1');
end;
/
alter session set sql_translation_profile = APP_FIX;
select count(*) from orders where status = :b1;
Без профиля план был INDEX RANGE SCAN, с профилем - TABLE ACCESS FULL, DBMS_XPLAN показывает текст уже с хинтом. Проверил на Oracle 26ai (23.26) и 18c, ведёт себя одинаково.
А если атрибут не ставить? По умолчанию FOREIGN_SQL_SYNTAX = TRUE, и запросы из SQL*Plus не переводятся. Нужен ещё
alter session set events = '10601 trace name context forever, level 32', а для него - привилегия ALTER SESSION.Приложению профиль включают logon-триггером или через атрибут сервиса (DBMS_SERVICE).
Подсмотрел в интернете, как его используют
🔹 Чинят тормозящий запрос вендорского софта без релиза: находят SQL_ID в shared pool, регистрируют замену, вешают logon-триггер (пошаговый гайд). А в Panorama скрипт подмены генерится по SQL_ID.
🔹 Миграция с Sybase и SQL Server: транслятор переводит чужой диалект в оракловый, приложение почти не трогают. Под это пакет изначально и делали.
🔹 Обходят неправильные результаты - подменяют запрос на исправленный (Kerry Osborne).
🔹 Фокусы на конференциях 😄 - один и тот же запрос «магически» становится быстрым, а на деле его тихо перенаправили на другую таблицу (Julian Dontcheff).
Подводные камни
🔸 Текст должен совпасть один в один. Проверил: другой регистр, лишний пробел, перенос строки или бинд :b2 вместо :b1 - и подмены нет.
🔸 SQL внутри PL/SQL (и статический, и execute immediate) не переводится, только то, что шлёт клиент.
🔸 Права. Владельцу - CREATE SQL TRANSLATION PROFILE. Чтобы профиль работал у другого юзера:
grant use on sql translation profile ему (иначе ORA-24252) и grant translate sql on user app владельцу (иначе ORA-01031).🔸 Отключить подмену -
enable_sql_translation(..., false). Процедуры DISABLE_SQL_TRANSLATION нет.🔸 REGISTER_ERROR_TRANSLATION в SQL*Plus код ошибки не подменил - это для драйверов при миграции.
Итог
Чтобы просто подсунуть хинт, есть штатные SQL Patch и SQL Plan Baseline. А если надо переписать сам запрос, а код не ваш - DBMS_SQL_TRANSLATOR рабочий вариант.
Но раз уж применили тёмную магию - обязательно документируйте и передавайте знание команде. Иначе через полгода никто не вспомнит, почему прод выполняет не тот запрос, что в коде, и кто-то потратит неделю на расследование 🕵️
А вы встречали его в бою? Пишите в чатик 💬
С вами был Денис. Всем предсказуемых запросов 🤝
#oracle #sql #plsql #dbms_sql_translator #оптимизация #фишки #Denis_Kivilev
Канал Oracle Developer | Чатик 💬
Мини-курс Оптимизация: Быстрый старт 🚀
📱 YouTube 📱 ВКонтакте 📱 LinkedIn 📱Threads
RUTUBE
