М
Максим Иглин | Backend
@maximiglindgtl1.3K подп.
1.1Kпросмотров
83.4%от подписчиков
18 октября 2025 г.
📷 ФотоScore: 1.2K
Порядок выполнения SQL‑операторов Запрос пишем слева направо, но в каком порядке его выполняет СУБД? Мы пойдём верхнеуровнево, то есть без деталей конкретных алгоритмов планировщика и executor-а. Цель – сложить в голове правильную модель, на которой вы сможете построить больше уровней абстракций и разобраться с деталями реализации. Это логический порядок обработки данных в SQL, а не физический порядок исполнения плана. Реальный порядок может отличаться! Пример запроса SELECT DISTINCT u.id, u.name, AVG(o.total) AS avg_order FROM users u JOIN orders o ON o.user_id = u.id WHERE u.active = true AND o.created_at >= date_trunc('month', now()) GROUP BY u.id, u.name HAVING AVG(o.total) > 100 ORDER BY avg_order DESC LIMIT 10 OFFSET 5; Мы хотим: 10 активных пользователей за текущий месяц со средним чеком заказа > 100, отсортированных по убыванию их среднего чека. 1. FROM База начинает с того, что планировщик выбирает оптимальный способ доступа к таблицами и оценивает, сколько строк в каждой, какие есть индексы, какие столбцы понадобятся. FROM users u 2. JOIN Теперь таблицы соединяются. JOIN orders o ON o.user_id = u.id После JOIN PostgreSQL создаёт поток соединённых строк. Это не новая таблица, а временная структура в памяти, с которой он работает дальше. Тип соединения выбирается на основе плана: Nested Loop, Hash Join, Merge Join. 3. WHERE Фильтрация лишних строк – всё, что не пройдёт условие, выкидывается. WHERE u.active = true AND o.created_at >= date_trunc('month', now()) Чем раньше база отсеет ненужное, тем меньше ей потом группировать, сортировать и агрегировать. На практике данный этап может быть объединен с JOIN. 4. GROUP BY Группировка оставшихся строк. GROUP BY u.id, u.name Теперь база собирает строки по ключам, например, все заказы одного пользователя, и готовится считать агрегаты (AVG, SUM, COUNT и др.). 5. HAVING Второй фильтр, только теперь по сгруппированным данным. HAVING AVG(o.total) > 100 WHERE работает с отдельными строками, а HAVING – с группами. Если средний чек < 100, то пользователь исключается из результата. 6. SELECT Теперь выбираются нужные колонки и вычисляются выражения. SELECT u.id, u.name, AVG(o.total) AS avg_order Это момент, когда результат начинает “принимать форму” будущей таблицы. 7. DISTINCT Удаляются дубликаты: SELECT DISTINCT ... Чтобы выполнить DISTINCT, PostgreSQL либо сортирует строки, чтобы сравнить подряд, либо строит хеш-таблицу, но в обоих случаях это требует времени и памяти. 8. ORDER BY Сортировка результата. ORDER BY avg_order DESC Если есть подходящий индекс, сортировка может быть почти бесплатной. Если нет, PostgreSQL сортирует набор строк, полученных после всех предыдущих стадий. При большом объёме данных может потребоваться временный файл (tmp) на диске, что называется внешней сортировкой. 9. LIMIT / OFFSET Отбираются нужные строки: LIMIT 10 OFFSET 5 Если порядок уже известен (ORDER BY), PostgreSQL может остановиться после получения нужного количества строк. Это экономит ресурсы. SQL-запросы выполняются не в том порядке, как мы их пишем. Это важно, потому что структура запроса напрямую влияет на то, сколько данных придётся читать, фильтровать, сортировать. Если представить, что у нас обычный жёсткий диск(hdd), что достаточно архаично с дешевыми SSD, то диски любят последовательное чтение. Вращающаяся пластина и механическая головка: чтобы считать данные, ей нужно доехать до нужной дорожки (seek-time) и дождаться сектора. Случайные чтения по рандомным местам здесь дорогие. Чем раньше ты отфильтруешь ненужное (WHERE), тем меньше случайных обращений к данным и тем быстрее всё остальное. Планировщик старается минимизировать объём данных, проходящих через стадии: чем раньше фильтрация, тем меньше нужно сортировать и группировать. Фильтрация раньше — меньше строк → меньше сортировок → меньше временных файлов. Индексы + порядок → можно просто прочитать данные по прямой, без прыжков по диску.
1.1K
просмотров
3935
символов
Нет
эмодзи
Да
медиа

Другие посты @maximiglindgtl

Все посты канала →
Порядок выполнения SQL‑операторов Запрос пишем слева направо — @maximiglindgtl | PostSniper