Задача по оптимизации
Полную постановку смотрите в посте вторника.
Объяснение
Типичная проблема при неправильном использовании механизмов СУБД. DBA очень часто негодуют по этому поводу.
Итак, поехали разбирать.
1️⃣ Представление v$sqlarea показывает все выполнявшиеся запросы в БД (parent-курсоры).
2️⃣ Каждый запрос имеет свой sql_id (уникальный номер), hash_value (хэш от текста запроса) и др.
3️⃣ Как только СУБД начинает выполнять запрос, происходит его парсинг. В том числе, берется hash от текста запроса и сравнивается с тем, что уже есть в SGA в кэше запросов. Если запрос не найден, то производится жесткий разбор (hard parse). В итоге, разобранный запрос помещается в кэш запросов.
Поменяете регистр одной буквы в запросе - это будет новый запрос и новый hard parse со всеми сопутствующими расходами.
Следующие запросы, с точки зрения БД, разные.
select * from tab1 where id = 1;
select * from tab1 where id = 2;
Для каждого будет сгенерирован свой sql_id, свой план(возможно), будут помещены в кэш-запросов и т.п. множество накладных расходов.
4️⃣ Для решения подобной ситуации используются переменные связывания (bind vars). Вместо жестко заданного литерала (1, 2…) используется подстановка значения:
select * from tab1 where id = :var;
теперь в var можно подставлять значения 1, 2…и т.д.
Не будет hard parse при подстановке значений. Не забивается кэш-запросов, DBA довольны.
Том Кайт в своей книге “Oracle для профессионалов” буквально на первых же страницах пишет про связные переменные.
Это было теоретическое введение.
Перейдем к нашему примеру.
Некое приложение соединяющееся c БД под пользователем ONE_C выполняло однотипный запрос аж 11166 раз (см. скриншоты ⬆️).
Текст запросов отличается ровно в одной детали - использование разных ID в предикате (where t1…. = число). Да, из задания это не совсем очевидно.
Поскольку в текстовом виде это абсолютно разные запросы, бедная СУБД выполнила аж 11166 раза hard pars забив кэш-запросов.
Решение простое. Использовать переменную связывания в предикате, в которую подставлять конкретное значение.
select ... where t1… = :id
будет выполнен 1 раз hard parse и всё.
⚠️ Не надо нагружать СУБД бесполезной никому не нужной нагрузкой
К сожалению, в рассматриваемой БД таких запросов не мало. Нужно явно править приложение 🛠
Этим грешат начинающие DBD, разработчики, пишущие на других языках, выполняющие запросы к СУБД Oracle.
Уровень задачи легкий, т.к. это должен знать каждый кто использует СУБД Oracle. Это основы.
На курсе по оптимизации будем разбирать множество интересных кейсов 😉
Обсудить в чатике
#оптимизация #решениезадачи