Главное правило SQL
Если в
Почему это важно?
В запросе ниже одна строка = одна должность (
Если пропустить неагрегированный столбец:
• Некоторые СУБД вернут ошибку
• Другие могут вернуть произвольное значение
• Запрос может «работать» сегодня, но завтра вернуть некорректный результат
Общее правило
Каждый столбец в
👉 @SQLPortal
GROUP BY, которое должен знать каждыйЕсли в
SELECT используются неагрегированные столбцы, убедитесь, что они добавлены в GROUP BY. Это не просто хорошая практика — в некоторых базах данных это обязательное требование.Почему это важно?
GROUP BY определяет, что представляет собой одна строка результата. База данных должна точно понимать, какое единственное значение поместить в каждую ячейку этой строки.В запросе ниже одна строка = одна должность (
job_title) внутри конкретного отдела (department). Поэтому и department, и job_title должны присутствовать в GROUP BY.Если пропустить неагрегированный столбец:
• Некоторые СУБД вернут ошибку
• Другие могут вернуть произвольное значение
• Запрос может «работать» сегодня, но завтра вернуть некорректный результат
Общее правило
Каждый столбец в
SELECT должен быть функционально зависим от GROUP BY. Если внутри одной группы столбец может содержать несколько значений, его нужно либо добавить в GROUP BY, либо использовать с агрегатной функцией.Please open Telegram to view this post
VIEW IN TELEGRAM
👍4💊1
Я написал два почти одинаковых SQL-запроса.
Один оказался в 451 раз быстрее. Я реализовывал cursor pagination и добавил composite index, чтобы ускорить запрос. Но вместо этого он стал медленнее.
Query plan показывал
После перехода на tuple comparison PostgreSQL смог эффективно использовать composite index. Время выполнения: 0,668 мс.
Та же логика pagination, но совершенно другой query plan.
Без проверки query plan эту проблему можно было бы легко пропустить.
👉 @SQLPortal
Один оказался в 451 раз быстрее. Я реализовывал cursor pagination и добавил composite index, чтобы ускорить запрос. Но вместо этого он стал медленнее.
Query plan показывал
Index Scan — так в чём же была проблема? Дело было не в размере dataset. Проблема заключалась в том, как сравнивались значения cursor.После перехода на tuple comparison PostgreSQL смог эффективно использовать composite index. Время выполнения: 0,668 мс.
Та же логика pagination, но совершенно другой query plan.
Без проверки query plan эту проблему можно было бы легко пропустить.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍2
Большой бесплатный гайд по SQL для начинающих
На freeCodeCamp лежит полноценный текстовый курс по SQL, который ведёт от самых основ до более серьёзных тем. Материал построен последовательно и подойдёт тем, кто только начинает разбираться в реляционных базах данных.
Внутри: таблицы и типы данных,
Хороший материал, чтобы системно пройти SQL с нуля или освежить базу.
👉 @SQLPortal
На freeCodeCamp лежит полноценный текстовый курс по SQL, который ведёт от самых основ до более серьёзных тем. Материал построен последовательно и подойдёт тем, кто только начинает разбираться в реляционных базах данных.
Внутри: таблицы и типы данных,
CRUD, SELECT и WHERE, constraints, агрегатные функции, подзапросы, нормализация, JOIN и основы оптимизации запросов. Для практики в курсе используется SQLite, при этом отдельно разбираются различия между SQL-базами.Хороший материал, чтобы системно пройти SQL с нуля или освежить базу.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
SQL-вопрос: Интересно, как вы ответите на этот вопрос.
Вы анализируете входы пользователей в систему и хотите узнать общее количество входов для каждого пользователя, но только для тех, кто входил более 5 раз. Вы пишете запрос:
Ну что, знатоки SQL, погнали!
👉 @SQLPortal
Вы анализируете входы пользователей в систему и хотите узнать общее количество входов для каждого пользователя, но только для тех, кто входил более 5 раз. Вы пишете запрос:
Ну что, знатоки SQL, погнали!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
ОЧЕНЬ ПЛОХАЯ ПРИВЫЧКА
Зачем вообще использовать номера позиций столбцов в
Ну серьёзно, ЗАЧЕМ, ЗАЧЕМ, ЗАЧЕМ? 😬
По-моему, это просто ленивый способ писать SQL-код. Всё, я это сказал.
Убедите меня, что я неправ.
👉 @SQLPortal
Зачем вообще использовать номера позиций столбцов в
GROUP BY?Ну серьёзно, ЗАЧЕМ, ЗАЧЕМ, ЗАЧЕМ? 😬
По-моему, это просто ленивый способ писать SQL-код. Всё, я это сказал.
Убедите меня, что я неправ.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3😁2💊1
SQL-фишка, о которой знают далеко не все
А вы знали, что внутри transaction можно создавать контрольные точки с помощью
Без
В этом случае будут отменены и заказ, и платёж.
С
Теперь можно откатить только неудачную часть transaction и продолжить работу с последней безопасной точки.
SAVEPOINT особенно полезен в сложных операциях, где полный откат и повторное выполнение всей transaction обходятся слишком дорого.
👉 @SQLPortal
А вы знали, что внутри transaction можно создавать контрольные точки с помощью
SAVEPOINT? Обычный ROLLBACK отменяет всю transaction. А SAVEPOINT позволяет создать точку, к которой можно откатиться, отменив только изменения, сделанные после неё.Без
SAVEPOINT:BEGIN;
INSERT INTO orders VALUES (1, 'Laptop');
INSERT INTO payments VALUES (1, 'FAILED');
-- Что-то пошло не так
ROLLBACK;
В этом случае будут отменены и заказ, и платёж.
С
SAVEPOINT:BEGIN;
INSERT INTO orders VALUES (1, 'Laptop');
SAVEPOINT before_payment;
INSERT INTO payments VALUES (1, 'FAILED');
-- Платёж не прошёл
ROLLBACK TO SAVEPOINT before_payment;
-- Пробуем другой способ оплаты
INSERT INTO payments VALUES (1, 'SUCCESS');
COMMIT;
Теперь можно откатить только неудачную часть transaction и продолжить работу с последней безопасной точки.
SAVEPOINT особенно полезен в сложных операциях, где полный откат и повторное выполнение всей transaction обходятся слишком дорого.
SAVEPOINT не предотвращает ошибку. Он просто помогает не откатывать всю работу из-за одной неудачной операции.Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Проверка уникальности работает через
Postgres не может доказать равенство двух
Простой пример, где это ломается, — составной ключ:
В итоге можно получить две активные записи membership для одного и того же пользователя, потому что ограничение уникальности вообще не срабатывает.
Начиная с Postgres 15, уникальные ограничения и индексы могут считать
Второй
Но это также запретит две строки с одинаковым значением
Частичный уникальный индекс
Если уникальность нужно обеспечить только для активных строк, используйте partial unique index:
👉 @SQLPortal
=, а NULL = NULL не даёт true. По умолчанию NULL не считается уникальным значением.Postgres не может доказать равенство двух
NULL, поэтому пропускает обе строки.Простой пример, где это ломается, — составной ключ:
-- UNIQUE (user_id, org_id, deleted_at)
INSERT INTO memberships VALUES (1, 10, NULL);
INSERT INTO memberships VALUES (1, 10, NULL);
-- обе строки будут вставлены
В итоге можно получить две активные записи membership для одного и того же пользователя, потому что ограничение уникальности вообще не срабатывает.
NULLS NOT DISTINCTНачиная с Postgres 15, уникальные ограничения и индексы могут считать
NULL равными:UNIQUE NULLS NOT DISTINCT (user_id, org_id, deleted_at)
Второй
INSERT уже завершится ошибкой.Но это также запретит две строки с одинаковым значением
deleted_at, а не только две активные строки.Частичный уникальный индекс
Если уникальность нужно обеспечить только для активных строк, используйте partial unique index:
CREATE UNIQUE INDEX ON memberships (user_id, org_id)
WHERE deleted_at IS NULL;
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2🔥1
Самый чистый способ получить последнюю запись для каждого пользователя
Можно фильтровать результаты window functions, таких как
Вместо:
Можно написать:
👉 @SQLPortal
Можно фильтровать результаты window functions, таких как
ROW_NUMBER() или RANK(), напрямую — без дополнительного subquery или CTE.Вместо:
WITH ranked AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY timestamp DESC
) AS rn
FROM events
)
SELECT *
FROM ranked
WHERE rn = 1;
Можно написать:
SELECT *
FROM events
QUALIFY ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY timestamp DESC
) = 1;
QUALIFY особенно удобен для deduplication, выбора последних записей и очистки данных. Он заметно уменьшает вложенность запросов и делает SQL проще для чтения. Только не забудьте проверить, поддерживает ли ваша СУБД QUALIFY.Please open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1
Please open Telegram to view this post
VIEW IN TELEGRAM