Пользователи часто хотят получать отчёты из базы данных, адаптированные под их нужды; запросы на такую кастомизацию могут со временем превратить систему в нечто вроде
Товарищ рассказывает историю одной такой системы, где в итоге один из пользователей удалил критичные данные:
https://idiallo.com/blog/sql-injection-as-a-feature
Берегите свои данные, коллеги!🐒
👉 @SQLPortal
SQL-инъекции как сервис
Товарищ рассказывает историю одной такой системы, где в итоге один из пользователей удалил критичные данные:
https://idiallo.com/blog/sql-injection-as-a-feature
Берегите свои данные, коллеги!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍1🔥1
Подготовленные выражения / параметризованные запросы в Postgres
Подготовленные выражения — это повторно используемые SQL-запросы, которые позволяют обойти стадию планирования, повторно используя уже построенный план выполнения и подставляя разные данные.
Полноценный SQL-запрос в Postgres проходит через следующие этапы:
- Парсинг — преобразование в внутреннее представление;
- Переписывание / трансформация — применение правил переписывания запроса, создание внутренних представлений (например, CTE или view);
- Планирование — планировщик Postgres использует статистику по таблицам и другую информацию, чтобы выбрать оптимальный план выполнения;
- Выполнение — непосредственный запуск запроса.
Подготовленные выражения используют тот же SQL и сохраняют первые три шага. Это значит, что при выполнении остаётся только извлечь данные — Postgres может полностью пропустить стадию планирования.
Пример
Подготовить запрос и сохранить план выполнения
Выполнить с одним параметром
Выполнить с другим параметром
Освободить ресурсы
ORM'ы часто работают с подготовленными выражениями, и это может значительно повысить производительность приложений. Со стороны приложения такие запросы обычно называют параметризованными. Параметризованный запрос содержит плейсхолдеры, которые заполняются значениями позже. Такой запрос на стороне БД превращается в подготовленное выражение.
Примеры в коде
В Rails:
В Python:
👉 @SQLPortal
Подготовленные выражения — это повторно используемые SQL-запросы, которые позволяют обойти стадию планирования, повторно используя уже построенный план выполнения и подставляя разные данные.
Полноценный SQL-запрос в Postgres проходит через следующие этапы:
- Парсинг — преобразование в внутреннее представление;
- Переписывание / трансформация — применение правил переписывания запроса, создание внутренних представлений (например, CTE или view);
- Планирование — планировщик Postgres использует статистику по таблицам и другую информацию, чтобы выбрать оптимальный план выполнения;
- Выполнение — непосредственный запуск запроса.
Подготовленные выражения используют тот же SQL и сохраняют первые три шага. Это значит, что при выполнении остаётся только извлечь данные — Postgres может полностью пропустить стадию планирования.
Пример
Подготовить запрос и сохранить план выполнения
PREPARE get_user_by_email (text) AS
SELECT * FROM users WHERE email = $1;
Выполнить с одним параметром
EXECUTE get_user_by_email('alice@test.com');
Выполнить с другим параметром
EXECUTE get_user_by_email('bob@test.com');
Освободить ресурсы
DEALLOCATE get_user_by_email;
ORM'ы часто работают с подготовленными выражениями, и это может значительно повысить производительность приложений. Со стороны приложения такие запросы обычно называют параметризованными. Параметризованный запрос содержит плейсхолдеры, которые заполняются значениями позже. Такой запрос на стороне БД превращается в подготовленное выражение.
Примеры в коде
В Rails:
User.where("email = ?", "alice@test.com")
В Python:
cur.execute("SELECT * FROM users WHERE email = %s", ("alice@test.com",))
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍1🔥1
Новичок в использовании
Попробуй этот простой веб-учебник:
https://crunchydata.com/developers/playground/query-performance-analytics
💡 Там есть пара отличных запросов, которые стоит сохранить для дальнейшего использования.
👉 @SQLPortal
pg_stat_statements
для анализа производительности запросов в Postgres?Попробуй этот простой веб-учебник:
https://crunchydata.com/developers/playground/query-performance-analytics
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
Новая фича в PostgreSQL 17 — геймчейнджер
Эта новая возможность в PostgreSQL 17 настоящая революция.
🔸 Механика страниц в PostgreSQL
PostgreSQL, как и большинство СУБД, работает с страницами фиксированного размера.
Практически всё — таблицы, индексы и т.д. хранится в виде страниц размером 8 КБ.
Каждая страница содержит:
- строки таблицы или кортежи индекса
- фиксированный заголовок
Страницы это просто байты в файлах. Они читаются и кэшируются в буферном пуле
Примеры чтения страниц:
- Страница 0:
- Страница 1:
- Страница 7:
Если таблица занимает 100 страниц, то для full table scan придётся выполнить 100 системных вызовов.
А каждый системный вызов имеет накладные расходы.
🔸 Что изменилось в Postgres 17
Добавили возможность объединения I/O:
- Можно указать, сколько страниц читать за один системный вызов
- Теоретически можно просканировать всю таблицу за один системный вызов
Это не всегда хорошая идея, подробнее об этом ниже.
Также добавили поддержку векторизованного I/O:
- Используется системный вызов
- Он принимает массив оффсетов и длин — удобно для произвольного чтения
🔸 Проблема: не читать лишнего
Допустим, мы делаем
1. Читаем страницу 0
2. Находим нужное → выходим
3. Остальные страницы не нужны
Теперь с новой фичей:
- Мы читаем сразу 10 страниц одним I/O
- Загружаем всё в shared buffers
- А нужное было уже на первой странице
> Результат — потрачены ресурсы (диск, память) впустую
🔸 Как это сбалансировать
Нужно будет находить баланс:
- Между эффективным I/O
- И избежанием избыточного чтения
🔸 Примечание
PostgreSQL действительно вызывает системный вызов ядра, чтобы читать по 8 КБ за раз.
Но ядро может быть настроено на read-ahead — заранее читать больше и кэшировать это в файловом кэше ОС.
👉 @SQLPortal
Эта новая возможность в PostgreSQL 17 настоящая революция.
PostgreSQL, как и большинство СУБД, работает с страницами фиксированного размера.
Практически всё — таблицы, индексы и т.д. хранится в виде страниц размером 8 КБ.
Каждая страница содержит:
- строки таблицы или кортежи индекса
- фиксированный заголовок
Страницы это просто байты в файлах. Они читаются и кэшируются в буферном пуле
Примеры чтения страниц:
- Страница 0:
read(offset=0, size=8192)
- Страница 1:
read(offset=8193, size=8192)
- Страница 7:
read(offset=57345, size=8192)
Если таблица занимает 100 страниц, то для full table scan придётся выполнить 100 системных вызовов.
А каждый системный вызов имеет накладные расходы.
Добавили возможность объединения I/O:
- Можно указать, сколько страниц читать за один системный вызов
- Теоретически можно просканировать всю таблицу за один системный вызов
Это не всегда хорошая идея, подробнее об этом ниже.
Также добавили поддержку векторизованного I/O:
- Используется системный вызов
preadv
- Он принимает массив оффсетов и длин — удобно для произвольного чтения
Допустим, мы делаем
seq scan
, чтобы найти значение:1. Читаем страницу 0
2. Находим нужное → выходим
3. Остальные страницы не нужны
Теперь с новой фичей:
- Мы читаем сразу 10 страниц одним I/O
- Загружаем всё в shared buffers
- А нужное было уже на первой странице
> Результат — потрачены ресурсы (диск, память) впустую
Нужно будет находить баланс:
- Между эффективным I/O
- И избежанием избыточного чтения
PostgreSQL действительно вызывает системный вызов ядра, чтобы читать по 8 КБ за раз.
Но ядро может быть настроено на read-ahead — заранее читать больше и кэшировать это в файловом кэше ОС.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤4
Media is too big
VIEW IN TELEGRAM
Интерактивная тренировка SQL
Если хочешь прокачать SQL на практике без установки СУБД и настройки окружения заходи на sqltest.online
👉 @SQLPortal
Если хочешь прокачать SQL на практике без установки СУБД и настройки окружения заходи на sqltest.online
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🔥5🌭3
Amazon Aurora стала первой OLTP базой данных, которая популяризировала разделение хранения данных и вычислительных ресурсов.
Главным новшеством стала переработка слоя хранения с целью минимизировать операции записи (write I/O) для преодоления задержек, связанных с сетью.
Как бы круто это ни было, она всё же не может превзойти локальные NVMe SSD.
Ссылка на статью:
https://pages.cs.wisc.edu/~yxy/cs764-f20/papers/aurora-sigmod-17.pdf
На видео показана PlanetScale Metal на AWS против Aurora. Те же CPU и объем памяти при I/O-насыщенной нагрузке, похожей на TPCC.
Значительно выше QPS при при этом в 3 раза ниже p99 задержка
👉 @SQLPortal
Главным новшеством стала переработка слоя хранения с целью минимизировать операции записи (write I/O) для преодоления задержек, связанных с сетью.
Как бы круто это ни было, она всё же не может превзойти локальные NVMe SSD.
Ссылка на статью:
https://pages.cs.wisc.edu/~yxy/cs764-f20/papers/aurora-sigmod-17.pdf
На видео показана PlanetScale Metal на AWS против Aurora. Те же CPU и объем памяти при I/O-насыщенной нагрузке, похожей на TPCC.
Значительно выше QPS при при этом в 3 раза ниже p99 задержка
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6
This media is not supported in your browser
VIEW IN TELEGRAM
База данных имеет право выполнять части SQL-выражения
Так как же избежать ошибок, если известно, что выражение может выбросить ошибку,
например, извлечение квадратного корня из отрицательного числа?
Используй
👉 @SQLPortal
WHERE
в любом порядке.Так как же избежать ошибок, если известно, что выражение может выбросить ошибку,
например, извлечение квадратного корня из отрицательного числа?
Используй
CASE
, чтобы выполнять вычисление только для допустимых значений:WHERE CASE
WHEN col > 0 THEN SQRT(col)
ELSE ...
END ...
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤6🔥4
JSON-реляционные duality views в Oracle Database 23ai — это гибкий, производительный и согласованный способ доступа к данным как:
- документам,
- реляционным таблицам,
- и к обоим одновременно💊
anders__swanson показывает, как создать базовые duality views для этого.
👉 @SQLPortal
- документам,
- реляционным таблицам,
- и к обоим одновременно
anders__swanson показывает, как создать базовые duality views для этого.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6
6 структур данных для экономии места в базе данных
👉 @SQLPortal
Фильтр Блума
Снижает стоимость поиска, проверяя, является ли элемент членом множества.
HyperLogLog
Оценивает количество уникальных элементов.
Cuckoo filter
Проверяет, принадлежит ли элемент множеству.
Minhash
Находит сходство между множествами.
SkipList
Эффективно ищет, вставляет и удаляет элементы из отсортированного списка.
Count-min sketch
Находит частоту элементов в большом потоке данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5
This media is not supported in your browser
VIEW IN TELEGRAM
Если ты хочешь изучить SQL или погрузиться в аналитику, начинай с Mode SQL Tutorial. У них всё работает прямо в браузере - никаких заморочек с установкой СУБД.
Что тебя ждёт:
— Basic SQL — SELECT, WHERE, ORDER BY, LIMIT и логические операторы;
— Intermediate SQL — агрегаты, GROUP BY, HAVING, JOINы;
— Advanced SQL — window functions, подзапросы, pivot’ы и performance-tuning;
— SQL Analytics Training — реальные кейсы аналитики, включая A/B тестирование и инсайты продукта.
👉 @SQLPortal
Что тебя ждёт:
— Basic SQL — SELECT, WHERE, ORDER BY, LIMIT и логические операторы;
— Intermediate SQL — агрегаты, GROUP BY, HAVING, JOINы;
— Advanced SQL — window functions, подзапросы, pivot’ы и performance-tuning;
— SQL Analytics Training — реальные кейсы аналитики, включая A/B тестирование и инсайты продукта.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4
Партиционирование таблиц в Postgres — это только для огромных таблиц? Вовсе нет.
Да, оно отлично подходит для обслуживания больших таблиц.
Но это ещё и полезный инструмент для управления данными и архивирования по мере роста базы.
Партиционирование разбивает одну большую таблицу на несколько меньших — по ключу партиционирования.
Например, по дате: отдельная таблица на каждый месяц, или по какому-нибудь полю вроде региона заказа.
Партиционирование помогает:
- Ускорить запросы — Postgres ищет только в нужном партиционе, а не во всей таблице
- Снизить блокировки, нагрузку на WAL и CPU во время обслуживания
- Упростить и структурировать архивирование
Пример
Представим, что у вас есть таблица с
Если просто сделать
- блокируются строки на несколько секунд
- создаётся большое количество WAL
- место освобождается не сразу
Возможно, придётся выполнять такую очистку вне продакшн-часов, чтобы не мешать работе приложения.
Но если таблица партиционирована по дате, вы можете:
- архивировать данные
- удалить нужную партицию (
Это не затронет активные данные и сразу освободит место.
Думаете, для партиционирования придётся переписывать приложение?
Обычно — нет.
Большинство приложений и ORM:
- работают с прозрачным партиционированием без проблем
- видят всё как одну таблицу
- а Postgres сам направляет запросы в нужные партиции
Всё работает без изменений в коде.
👉 @SQLPortal
Да, оно отлично подходит для обслуживания больших таблиц.
Но это ещё и полезный инструмент для управления данными и архивирования по мере роста базы.
Партиционирование разбивает одну большую таблицу на несколько меньших — по ключу партиционирования.
Например, по дате: отдельная таблица на каждый месяц, или по какому-нибудь полю вроде региона заказа.
Партиционирование помогает:
- Ускорить запросы — Postgres ищет только в нужном партиционе, а не во всей таблице
- Снизить блокировки, нагрузку на WAL и CPU во время обслуживания
- Упростить и структурировать архивирование
Пример
Представим, что у вас есть таблица с
500K
заказов. Если просто сделать
DELETE
за Q1 2023:- блокируются строки на несколько секунд
- создаётся большое количество WAL
- место освобождается не сразу
Возможно, придётся выполнять такую очистку вне продакшн-часов, чтобы не мешать работе приложения.
Но если таблица партиционирована по дате, вы можете:
- архивировать данные
- удалить нужную партицию (
DROP TABLE ...
)Это не затронет активные данные и сразу освободит место.
Думаете, для партиционирования придётся переписывать приложение?
Обычно — нет.
Большинство приложений и ORM:
- работают с прозрачным партиционированием без проблем
- видят всё как одну таблицу
- а Postgres сам направляет запросы в нужные партиции
Всё работает без изменений в коде.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤5
Что такое
В Postgres из коробки есть нативное партиционирование:
- Декларативный синтаксис партиционирования в
- Автоматическое отсечение партиций (partition pruning), когда запросы исключают нерелевантные партиции
- Прозрачные DML-операции —
Что добавляет pg_partman:
- Автоматически создаёт новые партиции по расписанию
- Автоматически удаляет старые партиции по времени или количественным правилам
- Фоновый воркер для выполнения обслуживания без внешних заданий
https://github.com/pgpartman/pg_partman
👉 @SQLPortal
pg_partman
и что он добавляет к встроенному в Postgres партиционированию?В Postgres из коробки есть нативное партиционирование:
- Декларативный синтаксис партиционирования в
CREATE TABLE
- Автоматическое отсечение партиций (partition pruning), когда запросы исключают нерелевантные партиции
- Прозрачные DML-операции —
INSERT
/UPDATE
/DELETE
работают по всем партициям без дополнительной обработкиЧто добавляет pg_partman:
- Автоматически создаёт новые партиции по расписанию
- Автоматически удаляет старые партиции по времени или количественным правилам
- Фоновый воркер для выполнения обслуживания без внешних заданий
https://github.com/pgpartman/pg_partman
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - pgpartman/pg_partman: Partition management extension for PostgreSQL
Partition management extension for PostgreSQL. Contribute to pgpartman/pg_partman development by creating an account on GitHub.
🔥4❤3👍3
Postgres DOMAINs… лучше, чем CONSTRAINTs?
Например, если я хочу убедиться, что все даты рождения больше 1 января 1930 года, а все email-адреса валидны, я могу создать вот так:
При создании таблицы достаточно назначить типы
Если в базе есть несколько полей, хранящих дату рождения или email, логика для этих полей будет переиспользована и для дополнительных колонок.
🤔 DOMAIN vs CHECK CONSTRAINT
Может возникнуть вопрос - зачем использовать
Простой ответ:
Кроме того,
👉 @SQLPortal
DOMAIN
позволяет задать конкретную проверку значений.Например, если я хочу убедиться, что все даты рождения больше 1 января 1930 года, а все email-адреса валидны, я могу создать вот так:
CREATE DOMAIN date_of_birth AS date
CHECK (value > '1930-01-01'::date)
;
CREATE DOMAIN valid_email AS text
NOT NULL
CHECK (value ~* '^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+[.][A-Za-z]+$')
;
При создании таблицы достаточно назначить типы
date_of_birth и valid_email
соответствующим колонкам.Если в базе есть несколько полей, хранящих дату рождения или email, логика для этих полей будет переиспользована и для дополнительных колонок.
CREATE TABLE person_using_domains
(
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
firstname TEXT NOT NULL,
lastname TEXT NOT NULL,
birth_date date_of_birth,
email valid_email
);
Может возникнуть вопрос - зачем использовать
DOMAIN
, если можно просто навесить CHECK constraint
прямо на колонку?Простой ответ:
CHECK constraints
не так просто изменять — их нужно удалять и создавать заново.Кроме того,
DOMAIN
можно создать на уровне схемы, и если в нескольких таблицах есть колонки с email или датой рождения, можно использовать один DOMAIN
для управления всеми этими полями, тем самым централизуя логику.Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍4
Бросок кубика определяет исход атаки в D&D.
Поэтому знание распределения результатов бросков помогает выбрать правильное действие.
При этом нужно учитывать преимущество , помеху и удачу.
Sean D. Stuber показывает, как сделать это в Oracle SQL.
https://seanstuber.com/2025/07/29/using-sql-to-derive-dice-distributions-in-dnd/
👉 @SQLPortal
Поэтому знание распределения результатов бросков помогает выбрать правильное действие.
При этом нужно учитывать преимущество , помеху и удачу.
Sean D. Stuber показывает, как сделать это в Oracle SQL.
https://seanstuber.com/2025/07/29/using-sql-to-derive-dice-distributions-in-dnd/
Please open Telegram to view this post
VIEW IN TELEGRAM
Sean D. Stuber - Fear No SQL
Using SQL to derive dice distributions in D&D - Sean D. Stuber
In a previous article (Bringing APEX and PL/SQL to D&D) I used a package with formulas of predetermined distributions for rolling multiple dice. In this article I will show how I came up with those formulas. In each case of rolling multiple 20-sided dice…
❤2