Что такое SEQUENTIAL SCAN?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
SEQUENTIAL SCAN в базах данных
SEQUENTIAL SCAN (или Seq Scan) — это метод сканирования таблицы в базе данных, когда база данных полностью проходит по всем строкам таблицы от начала до конца, чтобы найти нужные данные. Это самый базовый способ поиска, но не всегда самый эффективный.
Как это работает
Когда вы выполняете запрос без использования индексов, PostgreSQL (и другие БД) читают все страницы таблицы последовательно и проверяют каждую строку на соответствие условию запроса.
# Пример: SELECT без индекса
# SELECT * FROM users WHERE age > 30;
# PostgreSQL:
# 1. Открывает файл таблицы users
# 2. Читает первую страницу (например, 8KB данных)
# 3. Проверяет каждую строку: age > 30?
# 4. Если да — добавляет в результат
# 5. Переходит к следующей странице
# 6. Повторяет пока не прочитает всю таблицу
Пример из PostgreSQL EXPLAIN
import psycopg2
conn = psycopg2.connect("dbname=test user=postgres")
cur = conn.cursor()
# Посмотрим план выполнения запроса
cur.execute("EXPLAIN SELECT * FROM users WHERE age > 30;")
for row in cur.fetchall():
print(row)
# Вывод может быть примерно:
# Seq Scan on users (cost=0.00..1234.56 rows=5000)
# Filter: (age > 30)
Когда происходит SEQUENTIAL SCAN
1. Нет подходящего индекса
# Таблица users, индекс есть только на id
# Запрос ищет по age — используется Seq Scan
SELECT * FROM users WHERE age > 30; # Seq Scan
SELECT * FROM users WHERE id = 5; # Index Scan (быстро)
2. Индекс неэффективен для этого запроса
# Есть индекс на age, но запрос вернет большой результат
# Иногда Seq Scan быстрее, чем прыгать по индексу
SELECT * FROM users WHERE age > 10; # Может быть Seq Scan
3. Таблица очень маленькая
# Если таблица занимает всего 1-2 страницы (16KB),
# Seq Scan может быть даже быстрее, чем индекс поиск
SELECT * FROM small_config WHERE key = 'timeout';
Проблемы SEQUENTIAL SCAN
Плохое: Медленный на больших таблицах
# Таблица с 1 млн строк, каждая по 1KB
# Размер таблицы: 1GB
# Seq Scan должен прочитать все 1GB
# На диске это может быть медленно (сотни ms)
cur.execute("SELECT COUNT(*) FROM large_table WHERE status = 'active';")
# Seq Scan просмотрит все 1GB, хотя активных только 1000 записей
Хорошее: Использование всего доступного дискового IO
# PostgreSQL старается минимизировать количество операций чтения
# Читает последовательно, что лучше для HDD (очень плохой random access)
INDEX SCAN vs SEQUENTIAL SCAN
# Пример: таблица orders с 100000 записей
# Без индекса — SEQUENTIAL SCAN
SELECT * FROM orders WHERE customer_id = 5;
# cost=0.00..3000.00 — должен прочитать всю таблицу
# С индексом на customer_id — INDEX SCAN
CREATE INDEX idx_orders_customer ON orders(customer_id);
SELECT * FROM orders WHERE customer_id = 5;
# cost=0.10..4.50 — быстро прыгает по индексу
Оптимизация: как избежать SEQUENTIAL SCAN
1. Создание индекса
# Частые запросы по возрасту — создаем индекс
CREATE INDEX idx_users_age ON users(age);
# Теперь SEQUENTIAL SCAN вероятно не будет использоваться
SELECT * FROM users WHERE age > 30;
2. Анализ таблицы
# PostgreSQL использует статистику для выбора плана
# Если статистика устаревшая, может выбрать неправильный план
ANALYZE users; # Обновить статистику
3. Правильный выбор типа индекса
# BTREE индекс — для диапазонных запросов
CREATE INDEX idx_orders_date ON orders(order_date);
# Hash индекс — для точного сравнения
CREATE INDEX idx_users_email ON users(email) USING HASH;
# GiST, GIN — для специальных типов (JSON, полнотекстовый поиск)
CREATE INDEX idx_docs_content ON documents USING GIN(content);
4. Выборочные индексы
# Индекс только на активные заказы
CREATE INDEX idx_active_orders ON orders(customer_id)
WHERE status = 'active';
# Меньше данных в индексе, быстрее поиск
Когда SEQUENTIAL SCAN на самом деле нормально
# 1. Запрос выбирает большую часть таблицы
SELECT * FROM products WHERE price > 1; # Если почти все товары > $1
# 2. Таблица маленькая (< 100KB)
SELECT * FROM config;
# 3. Первое обращение к таблице
SELECT * FROM users ORDER BY created_at DESC LIMIT 10;
# Может быть быстрее, чем индекс, если не надо вся таблица
# 4. Сложные условия, которые трудно индексировать
SELECT * FROM users WHERE age > 18 AND (country = 'US' OR country = 'CA');
Проверка плана выполнения
import psycopg2
conn = psycopg2.connect("dbname=mydb")
cur = conn.cursor()
# Смотрим план
cur.execute("EXPLAIN ANALYZE SELECT * FROM users WHERE age > 30;")
for row in cur:
print(row[0])
# Вывод показывает:
# - Seq Scan или Index Scan
# - Estimated rows vs Actual rows
# - Estimated cost vs Actual time
Вывод
SEQUENTIAL SCAN — это когда база данных просматривает ВСЕ строки таблицы последовательно. Это:
- Медленно на больших таблицах
- Нормально на маленьких таблицах
- Легко оптимизируется индексами
- Иногда неизбежно и правильно
Для быстрых запросов нужно понимать, когда БД использует Seq Scan, и создавать правильные индексы.