Продолжим и сравним планы запросов двух вариантов более подробно ⚖️.
Вариант 1️⃣
⚠️ Оптимизатор вынужден применять аналитическую функцию и делать дополнительную фильтрацию.
Вариант 2️⃣
✅ Комментарий:
Во втором варианте Oracle просто спускается по индексу и берёт последнее значение — всё.
📎 Тестовый скрипт для проверки прикрепил.
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
Смотрите, анализируйте и пишите свои выводы в комментариях 👇
#RealInterviewTasks
Вариант 1️⃣
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 35 | 1 | 00:00:01 |
| * 1 | VIEW | | 1 | 35 | 1 | 00:00:01 |
| * 2 | WINDOW NOSORT STOPKEY | | 9367 | 327845 | 1 | 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID | RATES | 9367 | 327845 | 1 | 00:00:01 |
| * 4 | INDEX RANGE SCAN DESCENDING | RATES_U01 | 2 | | 1 | 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=1)
* 2 - filter(ROW_NUMBER() OVER ( ORDER BY INTERNAL_FUNCTION("R"."DATE_RATE") DESC )<=1)
* 4 - access("R"."CURR_ID"=9 AND "R"."DATE_RATE"<=SYSDATE@!-INTERVAL'+100 00:00:00' DAY(3) TO SECOND(0))
⚠️ Оптимизатор вынужден применять аналитическую функцию и делать дополнительную фильтрацию.
Вариант 2️⃣
----------------------------------------------------------
| Id | Operation | Name | E-Rows |
----------------------------------------------------------
| 0 | SELECT STATEMENT | | |
|* 1 | INDEX RANGE SCAN DESCENDING| RATES_U01 | 9367 |
----------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("R"."CURR_ID"=:B2 AND "R"."DATE_RATE"<=:B1")
✅ Комментарий:
Во втором варианте Oracle просто спускается по индексу и берёт последнее значение — всё.
📎 Тестовый скрипт для проверки прикрепил.
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
Смотрите, анализируйте и пишите свои выводы в комментариях 👇
#RealInterviewTasks
👎1🤯1
🎵«И нет нам покоя,
Гори, но живи!
Погоня, погоня,
Погоня, погоня
в горячей крови.»
🎬 к/ф Неуловимые мстители
✨ Недавно проходил собеседование в международную компанию.
От интервью вынес любопытный инсайт: обработка EXCEPTION "тормозит" работу.
Мысль показалась интересной, и я решил проверить её на практике ⚡
📊 Эксперимент
1️⃣ Создаём таблицу с числами от 1 до 1 000 000, но только с нечётными id:
2️⃣ В цикле от 1 до 1 000 000 считаем количество чётных и нечётных.
В первом варианте используем EXCEPTION NO_DATA_FOUND.
Во втором варианте вместо исключения применяем MAX, чтобы всегда получать результат.
⏱ Результат
Вариант с EXCEPTION:
time: +000000000 00:00:10.140000000
Вариант с MAX:
time: +000000000 00:00:09.921000000
📉 Разница: примерно 0.5 секунды на миллион строк.
🤔 Много это или мало — решать вам.
Но факт остаётся фактом: EXCEPTION действительно тормозит 🚀
Для проверки смотрим скрипт и анализируем.
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
💬 Пишите в комментах, всё что на душе наболело 👇
#Cases
Гори, но живи!
Погоня, погоня,
Погоня, погоня
в горячей крови.»
🎬 к/ф Неуловимые мстители
✨ Недавно проходил собеседование в международную компанию.
От интервью вынес любопытный инсайт: обработка EXCEPTION "тормозит" работу.
Мысль показалась интересной, и я решил проверить её на практике ⚡
📊 Эксперимент
1️⃣ Создаём таблицу с числами от 1 до 1 000 000, но только с нечётными id:
CREATE TABLE test (id NUMBER);
INSERT INTO test (id)
SELECT LEVEL
FROM dual
WHERE MOD(LEVEL, 2) = 1
CONNECT BY LEVEL <= 1000000;
COMMIT;
CREATE UNIQUE INDEX test_u01 ON test (id);
2️⃣ В цикле от 1 до 1 000 000 считаем количество чётных и нечётных.
В первом варианте используем EXCEPTION NO_DATA_FOUND.
Во втором варианте вместо исключения применяем MAX, чтобы всегда получать результат.
⏱ Результат
Вариант с EXCEPTION:
time: +000000000 00:00:10.140000000
Вариант с MAX:
time: +000000000 00:00:09.921000000
📉 Разница: примерно 0.5 секунды на миллион строк.
🤔 Много это или мало — решать вам.
Но факт остаётся фактом: EXCEPTION действительно тормозит 🚀
Для проверки смотрим скрипт и анализируем.
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
💬 Пишите в комментах, всё что на душе наболело 👇
#Cases
🤮2🔥1🤔1
📌 Самый простой вопрос из собесов на SQL. ❓ Что думаете, какой вариант даст TRUE?
Anonymous Poll
23%
NULL = NULL
68%
NULL != NULL
9%
NULL > NULL
👎2👍1
📌 Из предыдущего опроса стало ясно, что задачи на алгоритмы Вам интересны. Я прорешал около 💯 задач и понял, что почти все они делятся на 5 категорий:
Anonymous Poll
13%
Манипуляции с массивами
0%
Парсинг строк
13%
Работа с матрицами
13%
Структуры данных (деревья, стеки, очереди и т.д.)
0%
Динамическое программирование (каждое новое значение считается через предыдущие)
47%
Все интересны
13%
Достали уже "своими" алгоритмами
👎1😁1
🚀 Хотите прокачать SQL, но базы под рукой нет?
У Славы Рожнева — автора курса SQL в Яндексе — есть два классных ресурса:
🔹 sqltest.online — задачи и тесты для практики
📢 Канал: t.me/sqltestonline
🔹 sqlize.online — онлайн-песочница для SQL-запросов прямо в браузере
📢 Канал: t.me/sqlize
✨ Отличный вариант, чтобы учиться и держать форму в любом месте и в любое время.
#FriendlyResources
У Славы Рожнева — автора курса SQL в Яндексе — есть два классных ресурса:
🔹 sqltest.online — задачи и тесты для практики
📢 Канал: t.me/sqltestonline
🔹 sqlize.online — онлайн-песочница для SQL-запросов прямо в браузере
📢 Канал: t.me/sqlize
✨ Отличный вариант, чтобы учиться и держать форму в любом месте и в любое время.
#FriendlyResources
Telegram
SQLTest.online
Новости проекта SQLTest.online
🔥2👎1🤔1
DB developers channel
📌 Самый простой вопрос из собесов на SQL. ❓ Что думаете, какой вариант даст TRUE?
😅 Всё правильно — без подвоха на собесах редко бывает.
👉 Главное помнить: NULL — это "неизвестное значение", и любые сравнения (=, !=, <, >) с ним дают FALSE (результат сравнения неопределен).
✅ Рабочие варианты проверки:
1) NULL IS NULL → TRUE
2) Использовать функции NVL, COALESCE, CASE, DECODE, SYS_OP_MAP_NONNULL
Так что троллинг удался, но польза от вопроса всё равно осталась 🚀
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
#RealInterviewTasks #sql #Oracle #PLSQL
👉 Главное помнить: NULL — это "неизвестное значение", и любые сравнения (=, !=, <, >) с ним дают FALSE (результат сравнения неопределен).
✅ Рабочие варианты проверки:
1) NULL IS NULL → TRUE
2) Использовать функции NVL, COALESCE, CASE, DECODE, SYS_OP_MAP_NONNULL
Так что троллинг удался, но польза от вопроса всё равно осталась 🚀
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
#RealInterviewTasks #sql #Oracle #PLSQL
💯4👎1
🎵«Тем, кто рос в тепле и неге,
Мы, конечно, не коллеги.
Мы крапивные побеги,
Парни во.
Мы всегда и всюду рады
Вызывать у всех досаду,
Для чего нам это надо,
А не для чего.»
— к/ф «Тайна Снежной королевы» 🎬
🔥 А теперь — задачи для тех, кто любит алгоритмы и процедурные языки:
1️⃣ Максимальная разница — найти максимальную разницу в массиве, где больший элемент идёт после меньшего.
2️⃣ Проверка палиндрома — определить, является ли строка палиндромом (игнорируя регистр и лишние символы).
3️⃣ Максимальный квадрат — найти самый большой квадрат из единиц в двоичной матрице.
4️⃣ Максимальная глубина дерева — вычислить максимальную глубину бинарного дерева.
5️⃣ Дом-вор — дома стоят в ряд, нельзя грабить два подряд. Найдите максимальную сумму.
👉 Пробуем решать на PL/SQL или PL/pgSQL😉
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
#sql #Oracle #PostgreSQL #PLSQL #PLpgSQL
👎1👏1
DB developers channel
🎵«Тем, кто рос в тепле и неге, Мы, конечно, не коллеги. Мы крапивные побеги, Парни во. Мы всегда и всюду рады Вызывать у всех досаду, Для чего нам это надо, А не для чего.» — к/ф «Тайна Снежной королевы» 🎬 🔥 А теперь — задачи для тех, кто любит алгоритмы…
🎯 Задача 1. Максимальная разница
Дан массив чисел. Нужно найти максимальную разницу между двумя элементами, где больший элемент идёт после меньшего.
Пример:
😅 Сначала я решил задачу «в лоб» — двойным циклом.
🤖 Но ChatGPT подсказал вариант с одним проходом по массиву, и это действительно оптимально.
💻 Решение на PL/SQL:
⚡ Алгоритм (O(n)):
📌 minPref — минимальный элемент слева (купить дёшево).
📌 maxResidual — лучшая разница (продать дорого).
🔹 Шаги:
Инициализируем: minPref = "set"[1], maxResidual = NULL.
Для каждого следующего элемента i:
Считаем: cand = i - minPref.
Если cand > 0 и больше текущего maxResidual, обновляем результат.
Обновляем minPref = min(minPref, i).
Если так и не нашли пары → выводим «❌ пар нет».
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
👍 Пальцы вверх — продолжаем разбирать задачи по массивам.
👎 Пальцы вниз — значит, тема не зашла.
Дамы и Господа, выбор за вами 😉
#sql #Oracle #PLSQL
Дан массив чисел. Нужно найти максимальную разницу между двумя элементами, где больший элемент идёт после меньшего.
Пример:
[1, 3, 2, 5, 8, 7, 9]
Максимальная разница = 9 - 1 = 8
😅 Сначала я решил задачу «в лоб» — двойным циклом.
🤖 Но ChatGPT подсказал вариант с одним проходом по массиву, и это действительно оптимально.
💻 Решение на PL/SQL:
DECLARE
TYPE set_tab IS TABLE OF INTEGER;
"set" set_tab := set_tab (1, 3, 2, 5, 8, 7, 9);
minPref INTEGER;
maxResidual INTEGER := NULL;
cand INTEGER;
BEGIN
minPref := "set"(1);
FOR i IN 2 .. "set".COUNT LOOP
cand := "set"(i) - minPref;
IF cand > 0 THEN
IF maxResidual IS NULL THEN
maxResidual := cand;
ELSE
maxResidual := GREATEST(maxResidual, cand);
END IF;
END IF;
minPref := LEAST(minPref, "set"(i));
END LOOP;
IF maxResidual IS NOT NULL THEN
DBMS_OUTPUT.put_line('maxResidual = ' || maxResidual);
ELSE
DBMS_OUTPUT.put_line('No residual pairs');
END IF;
END;
⚡ Алгоритм (O(n)):
📌 minPref — минимальный элемент слева (купить дёшево).
📌 maxResidual — лучшая разница (продать дорого).
🔹 Шаги:
Инициализируем: minPref = "set"[1], maxResidual = NULL.
Для каждого следующего элемента i:
Считаем: cand = i - minPref.
Если cand > 0 и больше текущего maxResidual, обновляем результат.
Обновляем minPref = min(minPref, i).
Если так и не нашли пары → выводим «❌ пар нет».
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
👍 Пальцы вверх — продолжаем разбирать задачи по массивам.
👎 Пальцы вниз — значит, тема не зашла.
Дамы и Господа, выбор за вами 😉
#sql #Oracle #PLSQL
👍5❤1👎1
DB developers channel
🎵«Тем, кто рос в тепле и неге, Мы, конечно, не коллеги. Мы крапивные побеги, Парни во. Мы всегда и всюду рады Вызывать у всех досаду, Для чего нам это надо, А не для чего.» — к/ф «Тайна Снежной королевы» 🎬 🔥 А теперь — задачи для тех, кто любит алгоритмы…
🎯 Задача 2. Проверка палиндрома. Разбор по шагам
Цель: Проверка палиндрома: Проверьте, является ли заданная строка палиндромом, игнорируя регистр и небуквенно-цифровые символы..
📌 На входе:
"KaZAk" <=> "kAZaK"
🧠 Как работает алгоритм
1️⃣ Символ считается небуквой, если SUBSTR(lowerStr,i,1) = SUBSTR(upperStr,i,1)
(для букв lower != upper, для пробелов/знаков/цифр — одинаково; поэтому они пропускаются).
2️⃣ Сравнение идёт по буквам: SUBSTR(lowerStr, leftIndex#, 1) <=> SUBSTR(lowerStr, rightIndex#, 1).
3️⃣Если буквы совпали — сдвигаем оба индекса внутрь; если нет — isPolindrom := 'N' и выходим.
🧩 Что важно помнить
В текущей логике цифры тоже игнорируются, потому что для них lowerStr = upperStr.
Если нужен строгий режим «игнорируем только небуквенно-цифровые, но цифры учитываем», придётся скорректировать проверки.
👍 Пальцы вверх — продолжаем разбирать задачи по строкам.
👎 Пальцы вниз — значит, тема не зашла.
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
Дамы и Господа, выбор всегда за вами 😉
#sql #Oracle #PLSQL
Цель: Проверка палиндрома: Проверьте, является ли заданная строка палиндромом, игнорируя регистр и небуквенно-цифровые символы..
📌 На входе:
str := 'K 123 a?* Z(A) k ';
"KaZAk" <=> "kAZaK"
🧠 Как работает алгоритм
1️⃣ Символ считается небуквой, если SUBSTR(lowerStr,i,1) = SUBSTR(upperStr,i,1)
(для букв lower != upper, для пробелов/знаков/цифр — одинаково; поэтому они пропускаются).
2️⃣ Сравнение идёт по буквам: SUBSTR(lowerStr, leftIndex#, 1) <=> SUBSTR(lowerStr, rightIndex#, 1).
3️⃣Если буквы совпали — сдвигаем оба индекса внутрь; если нет — isPolindrom := 'N' и выходим.
DECLARE
str VARCHAR2 (4000) := 'K 123 a?* Z(A) k ';
lowerStr VARCHAR2 (4000) := LOWER (str);
upperStr VARCHAR2 (4000) := UPPER (str);
isPolindrom VARCHAR2 (1) := 'Y';
leftIndex# INTEGER := 1;
rightIndex# INTEGER := LENGTH (str);
BEGIN
WHILE leftIndex# < rightIndex# LOOP
--DBMS_OUTPUT.put_line ('---');
--DBMS_OUTPUT.put_line ('substr(lowerStr,leftIndex#,1) = ' || substr(lowerStr,leftIndex#,1));
--DBMS_OUTPUT.put_line ('substr(lowerStr,rightIndex#,1) = ' || substr(lowerStr,rightIndex#,1));
IF SUBSTR (lowerStr, leftIndex#, 1) = SUBSTR (upperStr, leftIndex#, 1) THEN -- не буква
leftIndex# := leftIndex# + 1;
CONTINUE;
END IF;
IF SUBSTR (lowerStr, rightIndex#, 1) = SUBSTR (upperStr, rightIndex#, 1) THEN -- не буква
rightIndex# := rightIndex# - 1;
CONTINUE;
END IF;
IF SUBSTR (lowerStr, leftIndex#, 1) = SUBSTR (lowerStr, rightIndex#, 1) THEN
leftIndex# := leftIndex# + 1;
rightIndex# := rightIndex# - 1;
ELSE
isPolindrom := 'N';
EXIT;
END IF;
END LOOP;
DBMS_OUTPUT.put_line ('isPolindrom = ' || isPolindrom);
END;
🧩 Что важно помнить
В текущей логике цифры тоже игнорируются, потому что для них lowerStr = upperStr.
Если нужен строгий режим «игнорируем только небуквенно-цифровые, но цифры учитываем», придётся скорректировать проверки.
👍 Пальцы вверх — продолжаем разбирать задачи по строкам.
👎 Пальцы вниз — значит, тема не зашла.
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
Дамы и Господа, выбор всегда за вами 😉
#sql #Oracle #PLSQL
👍5❤2👎1
Forwarded from Пишем на SQL (Ilia Khokhlov 👨💻)
Рекомендации по написанию программного кода хранимых функций и процедур
Чем больше нагрузка и больше одновременно выполняющихся транзакций, тем больше и ответственности при создании хранимых функций и процедур. Хорошо написанный программный код легко сопровождаем и не боится параллельной работы! Ниже собрал для вас основные рекомендации, которые важно учитывать при разработке хранимок (функций, процедур, триггеров).
1. Максимально эффективное обращение к данных (желательно всегда по первичным ключам и индексам);
2. Разделение сложных операций на более простые (сложный update, insert или delete с подзапросами можно упростить - сделать его по ключу, а данные, получаемые подзапросами, можно предварительно положить во временную таблицу или таблицу временного хранения данных);
3. Соблюдение идентичной последовательности работы с таблицами в разных функциях и процедурах (это позволит минимизировать вероятность взаимных блокировок);
4. Форматирование кода (соблюдение отступов, единое оформление, принятое в компании или в конкретной АС), использование регламентов оформления кода;
5. Соблюдение соответствия программы кода хранимки её назначению (процедура, открывающая вклад клиенту, должна открывать вклад клиенту и не должна дополнительно закрывать кредит);
6. Краткое и понятное комментирование неочевидных участков кода;
7. Идеальный код одной хранимки помещается на одном экране, чтобы не пришлось его прокручивать (конечно, на практике, это далеко не всегда так, но надо к этому стремиться). Если алгоритм большой, то его нужно разбивать на дополнительные функции и процедуры, которые можно использовать в коде основной функции/процедуры.
Чем больше нагрузка и больше одновременно выполняющихся транзакций, тем больше и ответственности при создании хранимых функций и процедур. Хорошо написанный программный код легко сопровождаем и не боится параллельной работы! Ниже собрал для вас основные рекомендации, которые важно учитывать при разработке хранимок (функций, процедур, триггеров).
1. Максимально эффективное обращение к данных (желательно всегда по первичным ключам и индексам);
2. Разделение сложных операций на более простые (сложный update, insert или delete с подзапросами можно упростить - сделать его по ключу, а данные, получаемые подзапросами, можно предварительно положить во временную таблицу или таблицу временного хранения данных);
3. Соблюдение идентичной последовательности работы с таблицами в разных функциях и процедурах (это позволит минимизировать вероятность взаимных блокировок);
4. Форматирование кода (соблюдение отступов, единое оформление, принятое в компании или в конкретной АС), использование регламентов оформления кода;
5. Соблюдение соответствия программы кода хранимки её назначению (процедура, открывающая вклад клиенту, должна открывать вклад клиенту и не должна дополнительно закрывать кредит);
6. Краткое и понятное комментирование неочевидных участков кода;
7. Идеальный код одной хранимки помещается на одном экране, чтобы не пришлось его прокручивать (конечно, на практике, это далеко не всегда так, но надо к этому стремиться). Если алгоритм большой, то его нужно разбивать на дополнительные функции и процедуры, которые можно использовать в коде основной функции/процедуры.
❤1👎1🤮1
Пишем на SQL
Рекомендации по написанию программного кода хранимых функций и процедур Чем больше нагрузка и больше одновременно выполняющихся транзакций, тем больше и ответственности при создании хранимых функций и процедур. Хорошо написанный программный код легко сопровождаем…
🎵«За що же ж мы боролись
За що же ж мы страждали
За що ж мы проливали нашу кровь?»
— (приписывается Борису Тимофееву)
Извините, но сегодня я включил режим "Душнилы" 🤓
Критиковать всегда проще, чем составить текст.
Все указанные правила — либо верны полностью, либо частично.
Мне стало интересно добавить другой формат — критический разбор.
1️⃣ Максимально эффективное обращение к данным
Тезис правильный 👍, но как это относится к коду? Никак.
Да, индексы и структура данных важны, но это скорее про хранение и доступ, а не про сам код.
Изначально индексы создаются с расчётом, что их будут использовать в коде. Но возможен и обратный анализ: индексы нужно добавлять, изменять или удалять, исходя из анализа кода.
2️⃣ Разделение сложных операций на простые
Операции не должны быть «простыми» или «сложными», они должны быть эффективными ⚡.
Если сложный запрос работает быстрее — переделывать его в «более простой» не нужно.
Вывод: всегда нужно проверять варианты и выбирать оптимальный. «Сложность» и «простота» — субъективны.
3️⃣ Единая последовательность работы с таблицами
В целом верно ✔️: одинаковая последовательность доступа к таблицам действительно снижает риск взаимных блокировок.
Но:
Не всегда это возможно.
Это лишь один из способов минимизации блокировок.
Закономерность есть, но правило не универсальное.
4️⃣ Форматирование кода
Тут согласен на 💯.
У каждой компании есть своё «самое лучшее» форматирование. Но к любому стилю быстро привыкаешь.
Единый стиль — это уважение к коллегам и к будущему себе.
5️⃣ Соответствие кода назначению
Полностью согласен 👍.
Метод должен делать ровно то, что написано в его имени.
Хочешь «открыть вклад» и «закрыть кредит»? Сделай три метода:
открыть_вклад
закрыть_кредит
открыть_вклад_и_закрыть_кредит
Да, странный метод 🤷, но принцип понятен: каждый метод выполняет свою задачу.
6️⃣ Комментарии в коде
Согласен, но с уточнением ✍️.
В 90% случаев комментарии появляются из-за проблем с неймингом или структурой кода.
Прежде чем написать комментарий, спроси себя:
не повторяю ли я имя метода?
не лучше ли переименовать или упростить код?
👉 В хорошем коде комментариев мало, но они цепляют внимание.
👉 В плохом коде комментариев много, и это выглядит как спам.
7️⃣ Код на одном экране
Здесь не согласен ❌.
Стремиться надо не к минимизации, а к простоте и читаемости.
Если метод состоит из 10 логических этапов, пусть будет 10 вызовов.
А вот искусственное деление ради «одного экрана» делает код трудным для анализа и изменений.
💬 Если есть возражение, согласие или негодование — милости просим в комментарии!
💎 Поддержка канала⁉️
#CodeArchitecture
За що же ж мы страждали
За що ж мы проливали нашу кровь?»
— (приписывается Борису Тимофееву)
Извините, но сегодня я включил режим "Душнилы" 🤓
Критиковать всегда проще, чем составить текст.
Все указанные правила — либо верны полностью, либо частично.
Мне стало интересно добавить другой формат — критический разбор.
1️⃣ Максимально эффективное обращение к данным
Тезис правильный 👍, но как это относится к коду? Никак.
Да, индексы и структура данных важны, но это скорее про хранение и доступ, а не про сам код.
Изначально индексы создаются с расчётом, что их будут использовать в коде. Но возможен и обратный анализ: индексы нужно добавлять, изменять или удалять, исходя из анализа кода.
2️⃣ Разделение сложных операций на простые
Операции не должны быть «простыми» или «сложными», они должны быть эффективными ⚡.
Если сложный запрос работает быстрее — переделывать его в «более простой» не нужно.
Вывод: всегда нужно проверять варианты и выбирать оптимальный. «Сложность» и «простота» — субъективны.
3️⃣ Единая последовательность работы с таблицами
В целом верно ✔️: одинаковая последовательность доступа к таблицам действительно снижает риск взаимных блокировок.
Но:
Не всегда это возможно.
Это лишь один из способов минимизации блокировок.
Закономерность есть, но правило не универсальное.
4️⃣ Форматирование кода
Тут согласен на 💯.
У каждой компании есть своё «самое лучшее» форматирование. Но к любому стилю быстро привыкаешь.
Единый стиль — это уважение к коллегам и к будущему себе.
5️⃣ Соответствие кода назначению
Полностью согласен 👍.
Метод должен делать ровно то, что написано в его имени.
Хочешь «открыть вклад» и «закрыть кредит»? Сделай три метода:
открыть_вклад
закрыть_кредит
открыть_вклад_и_закрыть_кредит
Да, странный метод 🤷, но принцип понятен: каждый метод выполняет свою задачу.
6️⃣ Комментарии в коде
Согласен, но с уточнением ✍️.
В 90% случаев комментарии появляются из-за проблем с неймингом или структурой кода.
Прежде чем написать комментарий, спроси себя:
не повторяю ли я имя метода?
не лучше ли переименовать или упростить код?
👉 В хорошем коде комментариев мало, но они цепляют внимание.
👉 В плохом коде комментариев много, и это выглядит как спам.
7️⃣ Код на одном экране
Здесь не согласен ❌.
Стремиться надо не к минимизации, а к простоте и читаемости.
Если метод состоит из 10 логических этапов, пусть будет 10 вызовов.
А вот искусственное деление ради «одного экрана» делает код трудным для анализа и изменений.
💬 Если есть возражение, согласие или негодование — милости просим в комментарии!
💎 Поддержка канала⁉️
#CodeArchitecture
👍1👎1🔥1
🎵«Я спросил у ясеня
Где моя любимая?
Ясень не ответил мне
Качая головой» — Сергей Никитин
Разбор задачи: найти максимальную глубину бинарного "ясеня".
Никогда прежде не имел опыта работы с такого рода объектами в PL/SQL.
Многому научился.😊
Возможно, правильнее все методы инкапсулировать в OBJECT node. Но для меня для тестовой задаче это уже слишком.
Где моя любимая?
Ясень не ответил мне
Качая головой» — Сергей Никитин
Разбор задачи: найти максимальную глубину бинарного "ясеня".
Никогда прежде не имел опыта работы с такого рода объектами в PL/SQL.
Многому научился.😊
Возможно, правильнее все методы инкапсулировать в OBJECT node. Но для меня для тестовой задаче это уже слишком.
CREATE OR REPLACE TYPE node IS OBJECT (
value NUMBER,
left REF node,
right REF node
);
CREATE TABLE nodes OF node;
DECLARE
root REF node;
PROCEDURE init_tree (node_amount IN INTEGER, root OUT REF node) IS
result REF node;
PROCEDURE insert_node (root IN OUT REF node, new_value IN NUMBER) IS
current node;
BEGIN
IF root IS NULL THEN
-- создаём корень
INSERT INTO nodes n
VALUES (node (VALUE => insert_node.new_value, left => NULL, right => NULL))
RETURNING REF (n)
INTO insert_node.root;
ELSE
SELECT DEREF (root) INTO current FROM DUAL;
IF new_value < current.VALUE THEN
insert_node (root => current.left, new_value => new_value);
-- обновляем left
UPDATE nodes n
SET n.left = current.left
WHERE REF (n) = insert_node.root;
ELSE
insert_node (root => current.right, new_value => new_value);
-- обновляем right
UPDATE nodes n
SET n.right = current.right
WHERE REF (n) = insert_node.root;
END IF;
END IF;
END insert_node;
BEGIN
FOR i IN 1 .. node_amount LOOP
DECLARE
newValue NUMBER := TRUNC (DBMS_RANDOM.VALUE (1, 100));
BEGIN
insert_node (root => result, new_value => newValue);
END;
END LOOP;
root := result;
END init_tree;
PROCEDURE print_tree (root IN OUT REF node) IS
current node;
skip EXCEPTION;
BEGIN
IF root IS NULL THEN
RAISE skip;
END IF;
SELECT DEREF (root) INTO current FROM DUAL;
DBMS_OUTPUT.put_line (
'node('
|| TO_CHAR (current.VALUE)
|| ','
|| CASE WHEN current.left IS NOT NULL THEN 'left = yes' ELSE 'left = no' END
|| ','
|| CASE WHEN current.right IS NOT NULL THEN 'right = yes' ELSE 'right = no' END
|| ')');
IF current.left IS NOT NULL THEN
print_tree (root => current.left);
END IF;
IF current.right IS NOT NULL THEN
print_tree (root => current.right);
END IF;
EXCEPTION
WHEN skip THEN
NULL;
END print_tree;
FUNCTION max_depth (root IN REF node)
RETURN INTEGER IS
current node;
leftDepth INTEGER;
rightDepth INTEGER;
BEGIN
IF root IS NULL THEN
RETURN 0;
END IF;
SELECT DEREF (root) INTO current FROM DUAL;
leftDepth := max_depth (current.left);
rightDepth := max_depth (current.right);
IF leftDepth > rightDepth THEN
RETURN leftDepth + 1;
ELSE
RETURN rightDepth + 1;
END IF;
END max_depth;
BEGIN
init_tree (node_amount => 10, root => root);
print_tree (root => root);
DBMS_OUTPUT.put_line ('Max depth is ' || TO_CHAR (max_depth (root => root)));
ROLLBACK;
END;
👎1🤬1
1️⃣ Подготовка структуры данных
Тип объекта:
node(value NUMBER, left REF node, right REF node) — значение и ссылки на детей.
Таблица хранения:
CREATE TABLE nodes OF node; — каждая строка — объект node.
Почему так: используется объектная модель Oracle: связи не по ID, а через REF/DEREF.🧩
2️⃣ Инициализация дерева — init_tree 🌱
Процедура init_tree (node_amount IN INTEGER, root OUT REF node) создаёт дерево и возвращает root.
Обратите внимание: в текущем виде цикл фиксирован на FOR i IN 1 .. node_amount
Внутри — вложенная процедура
insert_node(root IN OUT REF node, new_value IN NUMBER), которая строит бинарное дерево (вставляет меньшее влево, большее/равное вправо).
🧩 Ключевые моменты insert_node:
Если root IS NULL → создаём корень:
Иначе читаем текущий узел:
Рекурсивно вставляем в current.left или current.right:
insert_node(root => current.left, new_value => new_value);
Затем фиксируем изменённую ссылку в таблице:
UPDATE nodes n SET n.left = current.left WHERE REF(n) = insert_node.root; (или n.right = current.right).
Это важно, потому что мы меняли current как локальную копию, и нужно записать обновлённый REF обратно. 🧷
3️⃣ Печать дерева — print_tree 🖨️
print_tree(root IN OUT REF node) делает простой прямой обход (node → left → right):
Пропуск NULL через локальное исключение skip.
Для каждого узла — вывод value и флагов наличия детей (left = yes/no, right = yes/no).
Рекурсивный вызов для current.left и current.right.
Это удобный текстовый взгляд на структуру — помогает убедиться, что вставки шли правильно. 👀
4️⃣ Алгоритм глубины — max_depth 📏
База рекурсии: root IS NULL → 0.
Иначе DEREF(root) → current.
Рекурсивно считаем:
Возвращаем max(leftDepth, rightDepth) + 1.
Сложность:
По времени — O(n) (каждый узел посещаем ровно один раз).
По памяти стека — O(h), где h — высота дерева.
Поскольку дерево строится случайно (DBMS_RANDOM), оно не сбалансировано, и h может быть близко к n в худшем случае. 🎲
5️⃣ Точка входа блока 📦
init_tree(...) — строим дерево, получаем root.
print_tree(root) — показываем структуру.
DBMS_OUTPUT.put_line('Max depth is ' || max_depth(root)) — вывод глубины.
ROLLBACK; — данные не сохраняются: демонстрация без «мусора» в базе. ✅
6️⃣ Что важно помнить ⚠️
Работа с REF/DEREF требует обновления родителя после рекурсивной вставки — это и делает UPDATE ... WHERE REF(n) = insert_node.root;.
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
👍 Пальцы вверх — продолжаем разбирать задачи по структурам.
👎 Пальцы вниз — значит, тема не зашла.
Дамы и Господа, выбор всегда за вами 😉
#sql #Oracle #PLSQL
Тип объекта:
node(value NUMBER, left REF node, right REF node) — значение и ссылки на детей.
Таблица хранения:
CREATE TABLE nodes OF node; — каждая строка — объект node.
Почему так: используется объектная модель Oracle: связи не по ID, а через REF/DEREF.🧩
2️⃣ Инициализация дерева — init_tree 🌱
Процедура init_tree (node_amount IN INTEGER, root OUT REF node) создаёт дерево и возвращает root.
Обратите внимание: в текущем виде цикл фиксирован на FOR i IN 1 .. node_amount
Внутри — вложенная процедура
insert_node(root IN OUT REF node, new_value IN NUMBER), которая строит бинарное дерево (вставляет меньшее влево, большее/равное вправо).
🧩 Ключевые моменты insert_node:
Если root IS NULL → создаём корень:
INSERT INTO nodes ... RETURNING REF(n) INTO insert_node.root;
Иначе читаем текущий узел:
SELECT DEREF(root) INTO current FROM DUAL;
Рекурсивно вставляем в current.left или current.right:
insert_node(root => current.left, new_value => new_value);
Затем фиксируем изменённую ссылку в таблице:
UPDATE nodes n SET n.left = current.left WHERE REF(n) = insert_node.root; (или n.right = current.right).
Это важно, потому что мы меняли current как локальную копию, и нужно записать обновлённый REF обратно. 🧷
3️⃣ Печать дерева — print_tree 🖨️
print_tree(root IN OUT REF node) делает простой прямой обход (node → left → right):
Пропуск NULL через локальное исключение skip.
Для каждого узла — вывод value и флагов наличия детей (left = yes/no, right = yes/no).
Рекурсивный вызов для current.left и current.right.
Это удобный текстовый взгляд на структуру — помогает убедиться, что вставки шли правильно. 👀
4️⃣ Алгоритм глубины — max_depth 📏
FUNCTION max_depth(root IN REF node) RETURN INTEGER:
База рекурсии: root IS NULL → 0.
Иначе DEREF(root) → current.
Рекурсивно считаем:
leftDepth := max_depth(current.left);
rightDepth := max_depth(current.right);
Возвращаем max(leftDepth, rightDepth) + 1.
Сложность:
По времени — O(n) (каждый узел посещаем ровно один раз).
По памяти стека — O(h), где h — высота дерева.
Поскольку дерево строится случайно (DBMS_RANDOM), оно не сбалансировано, и h может быть близко к n в худшем случае. 🎲
5️⃣ Точка входа блока 📦
init_tree(...) — строим дерево, получаем root.
print_tree(root) — показываем структуру.
DBMS_OUTPUT.put_line('Max depth is ' || max_depth(root)) — вывод глубины.
ROLLBACK; — данные не сохраняются: демонстрация без «мусора» в базе. ✅
6️⃣ Что важно помнить ⚠️
Работа с REF/DEREF требует обновления родителя после рекурсивной вставки — это и делает UPDATE ... WHERE REF(n) = insert_node.root;.
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
👍 Пальцы вверх — продолжаем разбирать задачи по структурам.
👎 Пальцы вниз — значит, тема не зашла.
Дамы и Господа, выбор всегда за вами 😉
#sql #Oracle #PLSQL
👍2🤯2👎1
🎵«Пусть нету ни кола и ни двора,
Зато не платят Королю налоги
Работники ножа и топора,
Романтики с большой дороги.» — м/ф Бременские музыканты
🚨 Разбор задачи: Дом-вор 🏠💰
Условие:
Даны дома в ряд, каждый из которых имеет некоторую сумму денег.
❌ Нельзя грабить два смежных дома.
💡 Задача: найти максимальную сумму, которую можно украсть.
Пример:
Дома: 2 7 9 3 1
Максимальная сумма: 12
Формула из кода для каждого дома i:
💡 Пояснение:
matrix(i-1) — пропускаем текущий дом.
matrix(i-2) + houses(i) — грабим текущий дом, добавляем к сумме через один дом.
GREATEST выбирает максимальный вариант.
👍 Пальцы вверх — продолжаем разбирать задачи по динамическому программированию.
👎 Пальцы вниз — значит, тема не зашла.
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
Дамы и Господа, выбор всегда за вами 😉
#sql #Oracle #PLSQL
Зато не платят Королю налоги
Работники ножа и топора,
Романтики с большой дороги.» — м/ф Бременские музыканты
🚨 Разбор задачи: Дом-вор 🏠💰
Условие:
Даны дома в ряд, каждый из которых имеет некоторую сумму денег.
❌ Нельзя грабить два смежных дома.
💡 Задача: найти максимальную сумму, которую можно украсть.
Пример:
Дома: 2 7 9 3 1
Максимальная сумма: 12
DECLARE
TYPE matrix_tab IS TABLE OF NUMBER;
houses matrix_tab := matrix_tab (2, 7, 9, 3, 1);
matrix matrix_tab := matrix_tab ();
PROCEDURE print_matrix (matrix IN OUT NOCOPY matrix_tab) IS
str VARCHAR2 (100);
BEGIN
FOR i IN 1 .. matrix.COUNT LOOP
str := str || ' ' || TO_CHAR(matrix(i));
END LOOP;
DBMS_OUTPUT.put_line(str);
END print_matrix;
PROCEDURE get_thief_matrix (houses IN OUT NOCOPY matrix_tab, matrix IN OUT NOCOPY matrix_tab) IS
BEGIN
FOR i IN 1 .. houses.COUNT LOOP
IF i = 1 THEN
matrix.EXTEND;
matrix(matrix.COUNT) := houses(1);
ELSE
matrix.EXTEND;
matrix(matrix.COUNT) := GREATEST(
matrix(i-1),
CASE WHEN i <= 2 THEN 0 ELSE matrix(i-2) END + houses(i)
);
END IF;
END LOOP;
END get_thief_matrix;
BEGIN
print_matrix(matrix => houses);
get_thief_matrix(houses => houses, matrix => matrix);
print_matrix(matrix => matrix);
END;
Формула из кода для каждого дома i:
matrix(i) := GREATEST(
matrix(i-1),
CASE
WHEN i <= 2 THEN 0
ELSE matrix(i-2)
END + houses(i)
);
💡 Пояснение:
matrix(i-1) — пропускаем текущий дом.
matrix(i-2) + houses(i) — грабим текущий дом, добавляем к сумме через один дом.
GREATEST выбирает максимальный вариант.
👍 Пальцы вверх — продолжаем разбирать задачи по динамическому программированию.
👎 Пальцы вниз — значит, тема не зашла.
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
Дамы и Господа, выбор всегда за вами 😉
#sql #Oracle #PLSQL
👍3👎2
🎵«Если вы уже устали —
Сели-встали, сели-встали.
Не страшны вам Арктика с Антарктикой.» - В.С. Высоцкий
🚀 Простая задача с уникальными ключами и NULL 📝
Такая задача, вполне, может быть на собесе.
Спасибо подписчику Андрею. 😉
Условие:
Создаем таблицу с уникальным ограничением на два столбца и заполняем её NULL-значениями.
Нужно понять, как работает UNIQUE с NULL.
Какой будет результат?
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
Ваши решения и сомнения туда👇
#sql #Oracle #PostgreSQL #PLSQL #PLpgSQL
Сели-встали, сели-встали.
Не страшны вам Арктика с Антарктикой.» - В.С. Высоцкий
🚀 Простая задача с уникальными ключами и NULL 📝
Такая задача, вполне, может быть на собесе.
Спасибо подписчику Андрею. 😉
Условие:
Создаем таблицу с уникальным ограничением на два столбца и заполняем её NULL-значениями.
Нужно понять, как работает UNIQUE с NULL.
CREATE TABLE dropme_tt(
id INT,
a INT,
b INT,
CONSTRAINT tt_uk UNIQUE (a, b)
);
INSERT INTO dropme_tt (id, a, b)
SELECT level AS id, NULL AS a, NULL AS b
FROM dual
CONNECT BY level < 10;
SELECT * FROM dropme_tt;
Какой будет результат?
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
Ваши решения и сомнения туда👇
#sql #Oracle #PostgreSQL #PLSQL #PLpgSQL
👍1👎1
💬 Резюме: ИИ и будущее разработки
Вчера проходил собес (скорее, это была ознакомительная встреча) с CEO одной международной компании.
Мы также поговорили про влияние ИИ на разработку. Оказалось, что мой анализ ситуации полностью совпадает с его анализом и я решил свой анализ здесь озвучить.
🚀 Что умеет ИИ:
Решает SQL-задачи на уровне очень крепкого джуна / начинающего миддла.
Эффективен и быстрый в простых и стандартных задачах.
Инструмент для ускорения работы и тестирования.
⚠️ Ограничения:
В сложных решениях иногда ошибается.
Нужен синьор или эксперт для проверки и корректировки кода. (Пока нужен!!!)
💡 Влияние на рынок IT:
GPT, Gemini, Deepseek и другие меняют рынок:
Рутинная работа выполняется быстрее и качественнее, чем человеком.
В командах остаётся минимум людей (синьоров, экспертов).
💰 Карьерные выводы:
Зарплаты синьоров и экспертов будут расти 🚀.
Джуны будут работать за еду, в надежде когда-то стать синьорами.
✅ Общий вывод:
Ребята! Пока эта канитель внедряется в международных компаниях, но на местах она придет чуть позже.
Пока есть время!
Учитесь, перенимайте чужой опыт, не бойтесь сложных задач.
Именно, решение сложных задач поднимает из рутины.
💎 Поддержка канала⁉️
Вчера проходил собес (скорее, это была ознакомительная встреча) с CEO одной международной компании.
Мы также поговорили про влияние ИИ на разработку. Оказалось, что мой анализ ситуации полностью совпадает с его анализом и я решил свой анализ здесь озвучить.
🚀 Что умеет ИИ:
Решает SQL-задачи на уровне очень крепкого джуна / начинающего миддла.
Эффективен и быстрый в простых и стандартных задачах.
Инструмент для ускорения работы и тестирования.
⚠️ Ограничения:
В сложных решениях иногда ошибается.
Нужен синьор или эксперт для проверки и корректировки кода. (Пока нужен!!!)
💡 Влияние на рынок IT:
GPT, Gemini, Deepseek и другие меняют рынок:
Рутинная работа выполняется быстрее и качественнее, чем человеком.
В командах остаётся минимум людей (синьоров, экспертов).
💰 Карьерные выводы:
Зарплаты синьоров и экспертов будут расти 🚀.
Джуны будут работать за еду, в надежде когда-то стать синьорами.
✅ Общий вывод:
Ребята! Пока эта канитель внедряется в международных компаниях, но на местах она придет чуть позже.
Пока есть время!
Учитесь, перенимайте чужой опыт, не бойтесь сложных задач.
Именно, решение сложных задач поднимает из рутины.
💎 Поддержка канала⁉️
👍2👎1
🚀 Разбор простой, но коварной задачи про UNIQUE и NULL
(идея от подписчика Андрея — спасибо! 😉)
Вопрос: что произойдет при таком коде?
🔎 Разбор:
В UNIQUE участвуют (a, b).
В SQL NULL — это «неизвестное значение».
Два NULL не равны друг другу.
👉 Значит, для UNIQUE это разные значения, и конфликтов нет.
Да и на все NULL значения индекс B-tree не строится.
Итог: все 9 строк спокойно вставятся. Ошибки не будет.
📌 Результат в Oracle и PostgreSQL одинаковый:
Таблица заполнится строками с id = 1..9, а (a, b) везде будут (NULL, NULL).
✅ Важные замечания
Если бы на колонках стоял NOT NULL, фокус не прошёл бы.
👉 С этого и начинается консистентность данных — всегда анализируйте, может ли поле быть пустым.
На практике ограничения (CONSTRAINT ... UNIQUE) чаще создают отдельными командами:
Для DB разницы нет, а вот читать код человеку так проще.
Да и мы контролируем наименование индекса и не позволяем присваивать системные имена.
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
#RealInterviewTasks #sql #Oracle #PostgreSQL #PLSQL #PLpgSQL
(идея от подписчика Андрея — спасибо! 😉)
Вопрос: что произойдет при таком коде?
CREATE TABLE dropme_tt(
id INT,
a INT,
b INT,
CONSTRAINT tt_uk UNIQUE (a, b)
);
INSERT INTO dropme_tt (id, a, b)
SELECT level, NULL, NULL
FROM dual
CONNECT BY level < 10;
🔎 Разбор:
В UNIQUE участвуют (a, b).
В SQL NULL — это «неизвестное значение».
Два NULL не равны друг другу.
👉 Значит, для UNIQUE это разные значения, и конфликтов нет.
Да и на все NULL значения индекс B-tree не строится.
Итог: все 9 строк спокойно вставятся. Ошибки не будет.
📌 Результат в Oracle и PostgreSQL одинаковый:
Таблица заполнится строками с id = 1..9, а (a, b) везде будут (NULL, NULL).
✅ Важные замечания
Если бы на колонках стоял NOT NULL, фокус не прошёл бы.
👉 С этого и начинается консистентность данных — всегда анализируйте, может ли поле быть пустым.
На практике ограничения (CONSTRAINT ... UNIQUE) чаще создают отдельными командами:
CREATE TABLE dropme_tt
(
id INTEGER,
a INTEGER,
b INTEGER
);
CREATE UNIQUE INDEX dropme_tt_u01
ON dropme_tt (a, b);
Для DB разницы нет, а вот читать код человеку так проще.
Да и мы контролируем наименование индекса и не позволяем присваивать системные имена.
⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️
#RealInterviewTasks #sql #Oracle #PostgreSQL #PLSQL #PLpgSQL
👍2👎1
🎵 «Я вытяну счастливую карту…» — Земфира
✨ Сегодня суббота — отдыхаем от задач.
Запускаем рубрику «Полезные ресурсы» 🚀
🔗 Diffchecker (https://www.diffchecker.com/)
— простое и удобное web-средство для сравнения текста.
📌 Где может пригодиться:
быстро проверить изменения в SQL-скрипте или конфигурации;
сравнить два варианта кода;
увидеть, что именно поменялось в тексте документа.
⚡ Работает прямо в браузере, без установки.
💎 Поддержка канала⁉️
💡 Если у Вас есть свои полезные ссылки — не жадничайте, делитесь в комментах! 😉
#tools
✨ Сегодня суббота — отдыхаем от задач.
Запускаем рубрику «Полезные ресурсы» 🚀
🔗 Diffchecker (https://www.diffchecker.com/)
— простое и удобное web-средство для сравнения текста.
📌 Где может пригодиться:
быстро проверить изменения в SQL-скрипте или конфигурации;
сравнить два варианта кода;
увидеть, что именно поменялось в тексте документа.
⚡ Работает прямо в браузере, без установки.
💎 Поддержка канала⁉️
💡 Если у Вас есть свои полезные ссылки — не жадничайте, делитесь в комментах! 😉
#tools
👍3👎1