Oracle Developer👨🏻‍💻
3.22K subscribers
609 photos
68 videos
2 files
487 links
🔝 канал о разработке в СУБД Oracle:
SQL, PL/SQL, оптимизация, архитектура и многое другое...

Backend-pro.ru - обучение по различным программам, связанных с backend-разработкой для ФЛ и ЮЛ.

Отец-основатель: @denis_dbd Кивилёв Денис
Download Telegram
Медленно меняющееся измерение или Slowly changing dimension (SCD)

Как-то давно мы уже обсуждали подходы по хранению исторических данных. Я решил, немного раскрыть тему.
Основа - статья в Wiki на ENG (больше инфы) и RUS.

Есть некоторое количество подходов к хранению исторических данных. Кратко перечислю.

Тип 0. Данные не меняются
Изменения не фиксируются, т.к. данные в строках/полях не изменяются.

Тип 1. Полная замена
Историчность не соблюдается, новые данные записываются вместо старых. Нет никакой возможности получить предыдущие значения.

💡Этот тип встречается постоянно. Вы его используете по умолчанию.

Тип 2. Вставка новой строки с новой версией данных
Помимо основных полей, в таблице появляются служебные поля, которые обслуживают историю.

Например, столбец “Actual” = {0 - не актуальная версия, 1 - актуальная}. С “1” может быть только одна строка для какого-то конкретного экземпляра сущности. С “0” может быть несколько.

Или две даты, обозначающие период действия строчки - from/to. Для актуальной, самой последней строки, значение в date_to заполняется либо null, либо какой-то заглушкой типа 01.01.4000.
Еще могут быть различные вариации с монотонно растущими версиями и т.п.

Чтобы получить актуальную запись достаточно отфильтровать по столбцам Actual = 1 или date_to = 01.01.4000 или взять максимальную версию.

💡Довольно часто, встречается при решении реальных задач, когда требуется проследить всю историю изменений сущностей.

Тип 3. Добавление доп полей для хранения старых значений
В основной строке мы создаем доп поля, в которых хранятся предыдущие значения.
Как только строка меняется, то в основные поля попадают новые значения, а в доп поля старые значения. Используется такой подход для ограниченного количества полей, только по тем, которые интересует история. Естественно, сохраняется всегда только текущая версия и предыдущая, мы не сможем проследить всю историю изменений.

💡Не прям, частый кейс, но если требуется хранение только текущего и предыдущего значения ограниченного набора полей - почему нет.

Тип 4. Добавление таблицы с историей
В основной таблице хранится самая актуальная информация.
В дополнительной таблице хранятся все изменения. Она повторяет по структуре основную + доп служебные поля (дата изменения, может быть пользователь кто менял и т.п.)
Как только меняется основная таблица, информация тут же помещается в историческую.

💡Довольно часто, этот тип используется в аудитах/логах и т.д.

+ еще три типа, являющиеся разными комбинациями и/или расширениями первых четырех.

У каждого типа есть свои плюсы и минусы и кейсы использования. Рекомендую посмотреть статью на Вики.

К чему это все?
Можно использовать один из подходов для решения вчерашней задачки 😉

#scd #архитектура
Канал Oracle Developer | Чатик 💬
👍14
Решение задачи. Хранение истории заключения договоров

При решении задачи воспользуемся вторым подходом/типом SCD (см предыдущий пост).
Добавим два поле - дата ОТ и дата ДО действия строки.

create table contract(
contract_id number(38) not null, --PK
phone number(12) not null,
date_from date not null,
date_to date not null
);


Одномоментно, может быть только один активный контракт на один номер телефона. Добавим ограничение:
create unique index contract_phone_uq on contract(phone, date_to);

Активные записи будет помечаться “заглушкой” в date_to = 01.01.4000.
insert into contract values (1,79139331122, sysdate, date'4000-01-01');
insert into contract values (2,79139331155, sysdate, date'4000-01-01');

Для деактивации договора, достаточно найти по номеру телефона и “заглушке” актуальную запись и изменить значение в date_to на текущую дату.
update contract c
set c.date_to = sysdate
where c.phone = 79139331155
and c.date_to = date'4000-01-01';


При поиске истории по номеру телефона будет использоваться индекс contract_phone_uq:
select * from contract t where t.phone = 79139331155;


Для повторной регистрация пользователя и создание нового контракта на номер, который уже был в БД, достаточно опять произвести вставку с "заглушкой".
insert into contract values (3,79139331155, sysdate, date'4000-01-01');


В целом, мы реализовали то, что хотели. Итоговую историю, можно посмотреть на скриншоте ⬆️
Тут не хватает, некоторых штрихов, которые мы обсудим в следующих постах.

К слову сказать, такой подход неоднократно использовался в реальном банковском софте 👨🏻‍💻

Палец вверх, если понравилось 👍

#архитектура #решениезадачи
Канал Oracle Developer | Чатик 💬
👍281
Друзья, всем привет!

В прошлом году у нас проходил #конкурс с денежными призами на ТОП лучших задачек.
Помните, наверное, про бомжей, календари и другие 😉
Опыт оказался удачным - вам было интересно, коллеги получили денежку 💵

Предлагаю повторить. Всего будет 6 задачек по SQL или PL/SQL.

Призы
1️⃣ Авторам
1 место - 5К, 2 место - 3К, 3 место - 2К рублей.

2️⃣ Активному участнику в чате
Автор ответа (не важно на какую задачу), набравший максимальное количество реакций в чатике, будет так же одарен.

Кто хочет поучаствовать в качестве автора - прошу в личку 👌
Примеры задачек можно посмотреть по хештегу #конкурс

К сожалению, для призового фонда нужна денежка, поэтому реклама еще немного помозолит глаза 🤷🏻‍♂️

Oracle Developer
#конкурс
👍13🎉32
Задача. Удаление ненужных договоров

Вернемся к нашей задаче с договорами.

Бизнес решил, что закрытые договора, старше 5 лет (от даты закрытия), можно удалять из системы.
Данные эти не нужны.

Таблица, которую мы создали:
create table contract(
contract_id number(38) not null, --PK
phone number(12) not null,
date_from date not null,
date_to date not null
);


Уточнения:
🔸 практически все запросы в системе происходят к активным договорам;
🔸 в месяц заключается - 1M договоров, закрывается - 300K.

Какие есть варианты реализации бизнес требований?

Разбор задачи в четверг 🎓

Обсудить в чатике 💬

#задача
Oracle Developer
3
Решение задачи. Удаление не нужных договоров

При деактивации договора, в поле date_to проставляется текущая дата. Таких договоров, в месяц может быть - 300К.

Эту задачу можно решить, как минимум, двумя способами.
1️⃣ Применить Range-секционирование к таблице по дате закрытия договора - date_to.

Алгоритм: достаточно определить секцию для удаления, выполнить DDL-команду и всё.
alter table contract drop partition part_name update global indexes;



▫️ DDL команда на удаление выполнится моментально, практически не создав UNDO\REDO информации и нагрузки на БД.
▫️Активные договора всегда будут находится в самой последней секции с date_to = 01.01.4000. Можем попутно получить плюсы от секционирования, связанные с ускорением выполнения запросов.
▫️Не важно сколько данных удаляется 300К или 300М - всегда будет предсказуемое время работы.


▫️Таблицу необходимо переделать в секционированную, если она уже существует - это может быть проблемой (dbms_redifinition).
▫️Если обращение идет не по глобальному индексу (PK), то во всех запросах необходимо использовать ключ секционирования по date_to, иначе будут перебираться все секции. Запросы придется писать внимательно.
▫️DBA скептически относятся к выполнению DDL-команд на таблицах с глобальными индексами, даже с опцией update global indexes. Могут не пропустить такое решение.

2️⃣ Удалять данные пачками обычным DML
delete from contract where date_to < :delete_date and rownum < N;



▫️Не надо менять структуру таблицы;
▫️Достаточно простая реализация удаления пачками по N-строк ниже определенной даты.


▫️Создается дополнительная нагрузка на СУБД - генерация UNDO\REDO.
▫️При увеличении удаляемых данных выполнение начнет проседать, необходимо будет увеличивать частоту удалений и размер пачек. В итоге можно воткнуться в потолок, при котором придется переходить на секционирование.

———
И в первом и во втором случаях, функционал заворачивается в процедурку, которая вызывается из JOBа.

С 1м вариантом JOB запускается раз в сутки\несколько раз в месяц, со 2м вариантом чаще, например, раз в 1 час - удаляем мелкими пачками, чтобы распределить нагрузку в течение дня или удаляем всё ночью.

Кстати, можно создать комбинацию из 1го и 2го вариантов 😉

Палец вверх, если понравилось 👍

Обсудить в чатике плюсы и минусы решений 💬

Плаваете в секционировании? Велком в личку, есть что предложить 🎓

#архитектура #решениезадачи #секционирование
Канал Oracle Developer | Чатик 💬
👍542
Друзья, всем привет! 👋

В этот понедельник закончился уже второй поток курса "Oracle оптимизация SQL. Основы" 🎉

Ребята на протяжении 3.5 месяцев изучали тайны оптимизации СУБД, систематизировали знания, избавляясь от сумбура в голове, практиковались и решали проблемы.

Для меня самое главное, когда в обратной связи в ходе и по завершению курса ребята говорят 💬
🔸"Мне это уже пригодилось на работе"
🔸"У нас был тормозной запрос, а я взял и пофиксил его"
🔸"Вчера ко мне прибежали с проблемой, и буквально за час мы все решили" и т.д.

Прямо музыка для моих ушей. 🎶

Видео-отзывы коллег первого и второго потоков 🎥

Сегодня, чуть позже, анонсирую набор на третий поток.
Всего - 10 мест. 3 уже забронировано. Кто успел того и тапки. Пишите в
личку.

#оптимизация #курс
Канал Oracle Developer | Чатик 💬
🔥12👍102
🚀 Курс "Оптимизация Oracle SQL.Основы" - это отличная возможность освоить искусство оптимизации SQL запросов по уникальной программе "с нуля до уверенного специалиста, который может решать 80-90% типовых проблем".

Старт: 20е мая, окончание 29е августа.

Цели
🔺научиться находить и решать проблемы в PROD среде;
🔺научиться писать сразу оптимальные запросы;
🔺успешно проходить блок по оптимизации на собеседованиях;
🔺систематизировать знания.

Кратко
🔸теория по понедельникам, практика по четвергам, встречи в Zoom;
🔸11 домашних заданий + 7 тестов + курсовая работа;
🔸содержание курса структурировано таким образом, чтобы знания можно было применять уже после первой лекции.
🔸6 блоков с фокусом на решении реальных проблем:
1️⃣ Выявление проблемных запросов.
2️⃣ Чтение и понимание планов запросов.
3️⃣ Анализ планов запросов.
4️⃣ Решение проблем.
5️⃣ Внесение изменений.
(планы, хинты, awr,ash, v$active_session_history, статистика, трассировка, tkprof, nested loops, hash join, index, full table scan и многое многое другое).

Стоимость: 79K рублей или 42 тысячи рублей в рассрочку на 2 месяца (оплата любым способом из любой страны с чеком, крипта).
Сначала бронируйте участие. Оплата ближе к запуску.

Осталось мест: не осталось. Следующая возможность попасть на курс - сентябрь. Бронируйте заранее.

Минимальные требования: знаете SQL, имели опыт работы с PL/SQL, имеете представление о СУБД Oracle. Отлично, если сталкиваетесь с задачами по оптимизации и не можете их решить. Высокая мотивация дойти до конца. QA, аналитик, разработчик.

Отзывы
Видео-отзывы ребят первого и второго потоков. Скрины отзывов в посте выше. Если у вас есть сомнения, посмотрите.

Реальная жизнь
А теперь представьте себе такую ситуацию
К вам прибегают пользователи/аналитики/начальник и кричат "все пропало! все тормозит! нужно срочно решать проблему, PROD стоит!" 😱
Еще 5 минут назад вы предвкушали спокойный день, попивая халявный кофе на кофепоинте, весело общаясь с коллегой. А теперь нужно срочно куда-то бежать, что-то делать, решать проблему, которой "лучше бы не было". Вы просто обычный специалист, который ищет медленные запросы "через дебаг кода". Что делать будете? 😁

Можно еще усложнить, добавив в эту ситуацию то, что сломалась не ваша ламповая базенка в вашей же организации, до которой дотянуться легко и просто, а где-то на площадке заказчика, в банке😳
Прошел холодок по спине? Руки вспотели? Как дебажить будете? Полетите с Новосибирска в Москву (доступов то нет)? 😁

Ответы на курсе. Бронируйте пока еще есть 1 место Мест нет 🤷🏻‍♂️
Следующая возможность попасть на курс - сентябрь. Бронируйте заранее.

#оптимизация #курс
Канал Oracle Developer | Чатик 💬
🔥7👍3
SQL марафон из 5 задач с призом 🏆

Друзья, всем привет!

Решил попробовать новый формат. Это будут задачи для начинающих. Однако, мидлам и сеньерам тоже будет полезно размять мозг 🧠
Примерно такого уровня вопросы, мне попадались на собеседованиях на Java-разработчика.

Особенность - ответы будут сразу публиковаться с задачкой, но в скрытом режиме. Всего будет 5 постов-задач, с интервалом в 1.5 часа.

🔹Рекомендую, перед открытием спойлера, посидеть и подумать 😉
🔹Синтаксис, естественно, для Oracle.
🔹Я привожу не все возможные решения 👌
🔹Оставляем "за бортом" вопросы оптимизации.
🔹Определения для таблиц можно взять с репозитория
🔹Телега не позволяет использовать спойлер и SQL-форматирование одновременно😔

⚠️ Для интереса. Автору, опубликовавшему max количество оригинальных решений суммарно на все задачки в чатике, будет вручен денежный приз миллион - 5000 рублей или эквивалент USDT 💸💸 Добавляйте в ответ #решение_n.

Первая задача в 11:00 МСК

#задача #sql #марафон
Oracle Developer | Чат 💬
👍104🔥2
SQL марафон. Задача 1.

Постановка
Необходимо найти вторую по величине зарплату сотрудников (salary).
Сотрудники - таблица employees.

Решения
1️⃣
select max(salary)
from employees
where salary not in (select max(salary) from employees);

2️⃣
select max(salary) as secondhighestsalary
from employees
where salary &lt; (select max(salary) from employees);

3️⃣
select salary
from (select salary
,row_number() over(order by salary desc) as rnk
from employees)
where rnk = 2;


Опубликуйте свое решение в чатике с тегом #решение1 💬

#задача #sql #марафон
Канал Oracle Developer | Чатик 💬
👍72🔥1
SQL марафон. Задача 2.

Постановка
Найдите максимальную зарплату для каждого департамента.
Выведете - имя департамента (department_name) и максимальную зарплату для него (salary).
Если у департамента нет сотрудников - максимальная зарплата должна быть "0".
Отсортируйте по имени департамента.

Департаменты - таблица departments.
Сотрудники - таблица employees.

Решения
1️⃣
select d.department_name
,nvl(max(salary), 0)
from departments d
left join employees e on e.department_id = d.department_id
group by department_name
order by department_name;


2️⃣
select d.department_name,
nvl((select max(salary)
from employees e
where e.department_id = d.department_id), 0) as max_salary
from departments d
order by d.department_name;


Опубликуйте свое решение в чатике с тегом #решение2 💬

#задача #sql #марафон
Канал Oracle Developer | Чатик 💬
SQL марафон. Задача 3.

Постановка
Нужно найти сотрудников, которые работают дольше всех в своей должности (job_id).
Выведите все поля из таблицы employees.

Сотрудники - таблица employees.

Решения
1️⃣
select e.*
from employees e
where hire_date =
(select min(hire_date) from employees where job_id = e.job_id);


2️⃣
select e.*
from employees e
join (select job_id
,min(hire_date) min_hire_date
from employees
group by job_id) m
on e.job_id = m.job_id
and e.hire_date = m.min_hire_date;


Опубликуйте свое решение в чатике с тегом #решение3 💬

#задача #sql #марафон
Канал Oracle Developer | Чатик 💬
🤩1
SQL марафон. Задача 4.

Постановка
Нужно найти отделы с общей зарплатой сотрудников более 50000.
Вывести - ID отдела (department_id).

Сотрудники - таблица employees.

Решения
1️⃣
select department_id
from employees
group by department_id
having sum(salary) > 50000;


2️⃣
select d.department_id
from departments d
where (select sum(salary)
from employees e
where e.department_id = d.department_id) > 50000;


3️⃣
with dept_salaries as
(select department_id
,sum(salary) as total_salary
from employees
group by department_id)
select department_id
from dept_salaries
where total_salary > 50000;


Опубликуйте свое решение в чатике с тегом #решение4 💬

#задача #sql #марафон
Канал Oracle Developer | Чатик 💬
1👍1
SQL марафон. Задача 5.

Постановка
Нужно найти всех сотрудников, у которых зарплата выше средней зарплаты в таблице employees.
Вывести - все столбцы из таблицы employees.

Сотрудники - таблица employees.

Решения
1️⃣
select e.*
from employees e
where e.salary > (select sum(salary) / count(*) from employees);

2️⃣
with avg_sal as
(select avg(salary) as avg_salary from employees)
select e.*
from avg_sal a
join employees e on e.salary > a.avg_salary;


Опубликуйте свое решение в чатике с тегом #решение5 💬

#задача #sql #марафон
Канал Oracle Developer | Чатик 💬
Вот и закончился наш SQL-марафон 👯‍♀️

Победителя оглашу в пятницу. Так что у вас есть время догнать и перегнать 🏆
Напомню, засчитываются оригинальные решения:
🔸 не те, что скрываются под спойлером;
🔸 не те, которые опубликовали ДО вас.
Добавляйте в ответ тег #решениеN.

Приз - 5000 рублей или эквивалент в крипте (USDT) 😁

Все таки, основная цель марафона не заработать денег, а порешать задачки, которые могут встретиться на собеседованиях на Junior, Middle- позиции🎓

Если формат зайдет, будем периодически проводить такое 👍

По моим ощущениям, 5 запросиков в 1 день многовато.
Что думаете?
Обсудить в чатике 💬

#марафон
Канал Oracle Developer | Чатик 💬
👍13