.NET Разработчик: post #3293 — TG.ME

День 2750. #BestPractices #SQL
Как оптимизировать SQL-запросы. Часть 2

Часть 1

Часть II. Извлекайте только необходимые данные
Быстрее всего обрабатываются данные, которые вы не читаете. Каждый столбец и каждая строка, которые вы извлекаете, требуют операций ввода-вывода на диске, памяти и сетевого времени. Следующие методы позволяют максимально сократить результирующий набор данных на ранней стадии.

1. Прекратите использовать SELECT *
SELECT * извлекает все столбцы, включая те, которые вам не нужны. Это означает больше данных для чтения с диска, больше данных для передачи по сети и больше памяти для хранения — всё это для столбцов, которые ваш код игнорирует. Это также блокирует покрывающие индексы, когда индекс сам по себе может ответить на запрос, не затрагивая таблицу:
-- Плохо: извлечение всех столбцов
SELECT * FROM customers;

-- Хорошо: только используемые столбцы
SELECT customer_id, first_name, last_name
FROM customers;

Явное указание столбцов также безопаснее. Ваш запрос не изменит свою форму и не сломается незаметно, когда кто-то добавит или изменит порядок столбцов.

2. Фильтрация на ранних этапах
Чем меньше набор данных, с которым вы работаете, тем быстрее происходит обработка данных на последующих этапах. Возможно, вы слышали распространённый совет: «Применяйте наиболее избирательные фильтры в начале, чтобы сократить количество строк до того, как их обработают соединения и агрегирования».
SELECT o.order_id, o.total
FROM orders o
WHERE o.completed = true
AND o.order_date >= '2026-01-01'
AND o.order_date < '2026-02-01';

Замечание: в большинстве случаев не нужно размещать эти фильтры вручную. Современный стоимостной планировщик сам размещает предикаты в WHERE как можно раньше и самостоятельно переупорядочивает соединения. Изменение порядка в тексте предложения WHERE редко меняет план. На самом деле помогает предоставление планировщику селективного фильтра и индекса для его применения. Поэтому сосредоточьтесь на том, чтобы сделать фильтр удобным для индекса, а не на том, где он в запросе.

3. Keyset-пагинация вместо OFFSET, когда возможно
OFFSET кажется простым способом реализации пагинации, но чем глубже вы углубляетесь, тем медленнее она становится. Чтобы вернуть OFFSET 100000, БД прочитает и отбросит 100 000 строк перед ней. Keyset-пагинация (также называемая поисковой пагинацией) запоминает последнее увиденное значение и переходит непосредственно за него:
-- Keyset-пагинация по индексированному столбцу
SELECT * FROM orders
WHERE order_id > 1000
ORDER BY order_id
LIMIT 10;

Стоимость каждой страницы одинакова, будь то страница 2 или страница 2000, поскольку индекс переходит непосредственно к order_id > 1000.

Компромисс: keyset-пагинация обеспечивает быструю навигацию по следующей и предыдущей страницам, но вы не можете реализовать случайные переходы к любому номеру страницы.

4. Запрашивайте только то, что изменилось
Повторное чтение всей таблицы при каждом запуске неэффективно, если изменилось всего несколько строк. Отслеживайте «водяной знак» — последнюю обработанную точку — и извлекайте только строки, более новые, чем он:
-- Читаем только записи, обновлённые с последнего запуска
SELECT * FROM records
WHERE modified_date > '2026-08-10 00:00';

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

Продолжение следует…

Источник:
https://antondevtips.com/blog/how-to-optimize-sql-queries-20-proven-best-practices
👍4
August 11, 2026 1.4K 6 15