- •Введение.
- •Соединение с бд Oracle.
- •Типы данных Oracle, создание и модификация таблиц и вьюшек.
- •Задача. Удаление дубликатов.
- •Задача. Удаление по условию not in.
- •Функции по работе со строками.
- •Функции по работе с числами.
- •Задача. Факториал.
- •Задача. Подсчет числа вхождений символа в строку.
- •Троичная логика, конструкция with, функции nvl, coalesce, case, decode.
- •Основы pl/sql.
- •Задача. Подсчет числа вхождений подстроки в строку.
- •Задача. Копирование таблицы фиксированной структуры.
- •Задача. Простановка count в цикле.
- •Задача. Распределение данных по условию.
- •Задача. Использование сиквенсов и dbms_random.
- •Задача. Процедура с out параметрами. Нотации.
- •Задача. Простой пакет.
- •Задача. Разные виды Count.
- •Задача. Получение скрипта заполнения таблицы имеющимися данными.
- •Раздача прав (grants).
- •Операции над множествами, joins.
- •Задача. Сравнение множеств.
- •Задача. Загрузка данных с помощью full join.
- •Задача. Проставление роста животных.
- •Оператор merge.
- •Задача. Merge данных о студентах.
- •Задача. Merge данных о клиентах.
- •Функции по работе с датами.
- •Словарь данных.
- •Задача. Last_ddl_time.
- •Задача. Отчет об объектах текущей схемы.
- •Задача. Dbms_output из явного курсора по словарю данных.
- •Задача. Компиляция схемы.
- •Задача. Поиск текста во вьюшках.
- •Динамический sql.
- •Задача. Удаление конкретной таблицы, если она существует.
- •Задача. Удаление любой таблицы с проверкой на существование.
- •Задача. Конструкция '%rowcount'.
- •1) С помощью динамического вызова команды truncate очистить таблицу kk_objects_list от данных.
- •3) Вставить в таблицу kk_objects_list перечень имен всех объектов текущей схемы. С помощью конструкции sql%rowcount выдать в dbms_output количество вставившихся строк.
- •Задача. Удаление всех таблиц и вьюшек.
- •Часть 1. Написать pl/sql блок, который дропает все таблицы текущей схемы, начинающиеся на 'kk_'.
- •Часть 2. Написать pl/sql блок, который выдает в dbms_output скрипт удаления всех вьюшек текущей схемы, начинающихся с 'vw_kk%'.
- •Задача. Отчет о максимальных id.
- •Задача. Переименование столбцов.
- •Задача. Создание вьюшек.
- •Триггеры.
- •Задача. Автоинкрементное поле.
- •Задача. Триггер конвертации сумм в валюте.
- •Задача. Триггер логирования dml-операций.
- •Задача. Триггер зеркалирования.
- •Задача. Триггер по поиску в справочнике.
- •Задача. Триггер контроля.
- •Global temporary tables и переменные в заголовке пакета.
- •Переменные в заголовке пакета.
- •Регулярные выражения.
- •Задача. Правка некачественных данных регулярными выражениями.
- •Задача. Парсинг строк с помощью регулярных выражений.
- •Автономные транзакции.
- •Задача. Автономное логирование этапов загрузки.
- •Иерархические запросы.
- •Задача. Вывод иерархии с отступами.
- •Задача. Соединение иерархической таблицы с обычной.
- •Задача. Сумма зарплат подчиненных.
- •Задача. Простой календарь.
- •Задача. Детальный календарь.
- •Задача. Календарь с индикаторами выходных дней.
- •Аналитические функции.
- •Отступление о Rownum.
- •Негрупповые аналитические функции.
- •Групповая функция keep dense_rank.
- •Задача. Взятие последней записи о клиенте.
- •Задача. Отчет об изменениях зарплаты.
- •Задача. Пакет функций о вкладах.
- •Задача. Группировка лога выполнения процессов.
- •Задача. Вьюшка с аналитическими функциями по вкладам.
- •Задача. Календарь с аналитикой.
- •Задача. Поиск баланса счета на заданную дату.
- •Задача. Удаление исторических данных о рейтинге.
- •Функции, выдающие более одного значения.
- •Задача. Вызов многозначной функции.
- •"Расклейка" и "склейка" строк.
- •“Расклейка” одной строки.
- •“Расклейка” нескольких строк с группировкой.
- •“Склейка” в одну строку.
- •“Склейка” нескольких строк с группировкой.
- •Задача. Простая расклейка-склейка.
- •Задача. Скрипт создания индексов.
- •Задача. Скрипт создания таблиц.
- •Задача. Отчет о созданных объектах.
- •Задача. Отчет о числе строк в таблицах.
- •Задача. Расклейка списка хобби.
- •Задача. Склейка запроса о максимумах числовых полей.
- •Оптимизация запросов.
Оптимизация запросов.
Допустим, есть таблицы kk_op1 и kk_op2, которые надо соединить по ключам id.
Если мы хотим для каждой строки kk_op1 запрашивать значения из kk_op2, то можно использовать хинт use_nl (use nested loops). Неплохой результат можно получить, если есть индекс по kk_op2.id или в kk_op1 мало строк:
select /*+ use_nl(kk_op1 kk_op2)*/
*
from kk_op1, kk_op2
where kk_op1.id = kk_op2.id;
Если мы хотим попробовать построить hash по таблицам, считая, что поиск по индексу будет неэффективным, то можно использовать хинт use_hash:
select /*+ use_hash(kk_op1 kk_op2)*/
*
from kk_op1, kk_op2
where kk_op1.id = kk_op2.id;
Если мы хотим явно указать, что таблицу kk_op1 нужно сканировать по индексу IX_KK_OP1, то можно использовать хинт index:
select /*+ index(kk_op1 ix_kk_op1)*/
*
from kk_op1;
Если в запросе таблицам даны алиасы, то именно их нужно использовать в хинте, иначе хинт не будет работать.
Оптимизация запросов с помощью хинтов и модификации метода соединения таблиц не так эффективна, как изменение логики самого запроса.
Имеет смысл соединять маленькие по объему данных подзапросы, а не большие таблицы. Например, вместо запроса:
select a.id, a.f1, b.id, b.id2, b.f2, c.id, c.dt
from a, b, c
where a.id = b.id
and b.id2 = func(c.id)
and a.f1 = 'ограничение выборки'
and nvl(b.f2, '*') <> 'ограничение выборки2'
and c.dt between to_date('начало ограничения') and
to_date('конец ограничения');
стоит пробовать использовать запрос:
with aa as
(select /*+ materialize*/
id, f1
from a
where f1 = 'ограничение выборки'),
bb as
(select /*+ materialize*/
id, id2, f2
from b
where f2 <> 'ограничение выборки2'
or f2 is null /*использование nvl меняем на использование is null*/),
cc as
(select /*+ materialize*/
id, func(c.id) func_id /*рассчитанное поле, по которому будем соединять, материализуем*/, dt
from c
where dt between to_date('начало ограничения') and
to_date('конец ограничения'))
select aa.id, aa.f1, bb.id, bb.id2, bb.f2, cc.id, cc.dt
from aa, bb, cc /*стараемся соединять маленькие таблицы, а не большие*/
where aa.id = bb.id
and bb.id2 = cc.func_id;
Автору нравится использование конструкции WITH и хинта /*+ materialize*/, которое позволяет по ходу выполнения SQL-запроса фактически заниматься ETL-шагами, не занимаясь написанием create table as select.
Если же производится не оптимизация SQL-запроса, а оптимизация PL/SQL процедуры загрузки, то имеет смысл под каждый WITH создать промежуточную таблицу.
Затем в процедуре загрузки следует очищать эту промежуточную таблицу и заново заливать ее данными.
При этом продолжительность заполнения промежуточной таблицы, а также количество вставленных в нее строк разумно логировать в таблицу с логами.
По логам можно выявлять узкие места в загрузке и продолжать оптимизировать именно те загрузки в промежуточные таблицы, которые выполняются медленно.
