Тестирование баз данных

Почему тестирование запросов на производительность — ловушка для новичка
Начинающие разработчики часто оценивают скорость SQL-запроса по времени его первого выполнения. Это фундаментальная ошибка. База данных кеширует результаты и планы запросов, и второй запуск может быть в 100 раз быстрее. Профессионалы всегда прогревают кеш (например, выполняют SELECT COUNT(*) до замера) и используют команды SET STATISTICS TIME ON/IO ON в SQL Server или EXPLAIN ANALYZE в PostgreSQL. В 2026 году инструменты профайлеров, такие как pg_stat_statements для PostgreSQL или Query Store для SQL Server, дают точную картину, но только если вы знаете, как исключить влияние плана выполнения.
- Холодный vs горячий кеш: всегда измеряйте оба сценария — после перезапуска БД и после прогрева — разница покажет истинную нагрузку.
- План запроса не врёт: смотрите на операции Seq Scan (полное сканирование) — если они занимают >30% времени, нужен индекс или переписывание запроса.
- Фиксация IO: замеряйте логические и физические чтения страниц — физические чтения (диск) убивают производительность при параллельных запросах.
Но даже идеальный план выполнения не гарантирует успеха под нагрузкой. В реальном проекте база данных — это не один запрос, а оркестр сотен. Именно здесь скрывается второй профессиональный нюанс: тестирование конкурентности и блокировок.
Как отловить deadlock и полное зависание БД до релиза
Стандартное юнит-тестирование не показывает гонки за ресурсами. В 90% случаев deadlock возникает не из-за сложных запросов, а из-за неправильного порядка блокировок в транзакциях. Пример: первый запрос блокирует строку A, второй — строку B, затем первый ждёт B, а второй — A. Профессионалы используют системные представления, такие как sys.dm_tran_locks (MSSQL) или pg_locks (PostgreSQL), чтобы отследить цепочки ожидания. В обучающих курсах на нашей платформе мы заставляем студентов писать тесты, которые имитируют 10 параллельных сессий через многопоточные скрипты на Python или Go — это единственный способ воспроизвести реальный сценарий.
- Проверка изоляции транзакций: уровень READ COMMITTED (по умолчанию) допускает неповторяющееся чтение — для финансовых операций поднимайте до REPEATABLE READ или SERIALIZABLE.
- Таймауты блокировок: установите LOCK_TIMEOUT (MSSQL) или deadlock_timeout (PostgreSQL) на 5 секунд — если запрос ждёт дольше, значит дизайн таблиц или индексов неоптимален.
- Тестирование отката транзакции: принудительно вызовите ROLLBACK после частичного выполнения — проверьте, что все промежуточные состояния отменены без остатка (например, счёт не обнулился).
Ещё один малоизвестный аспект — тестирование «грязных» данных в условиях конкурентности. Если две транзакции одновременно обновляют одну строку без оптимистичной блокировки (версионирование строк), вы получаете потерянное обновление. Эту проблему ловит только тест с проверкой версии записи (UPDATE … WHERE version = :old_version).
Проверка целостности данных: что забывают в 2026 году
Многие считают, что если есть внешние ключи и ограничения UNIQUE, то данные корректны. Это иллюзия. Реальная утечка данных происходит в хранимых процедурах и триггерах, которые работают как чёрный ящик. На практике мы сталкиваемся с ситуацией, когда триггер AFTER INSERT меняет запись, нарушая бизнес-правило (например, уменьшает остаток на складе дважды). Профессионалы пишут тесты, которые вызывают триггеры с заведомо некорректными данными и проверяют, что в логи пишется ошибка, а операция откатывается. Важно также тестировать каскадные удаления: если вы удаляете родительскую запись, дочерние должны удалиться или обнулиться без потери связанных данных.
- Тестирование часовых поясов: храните время в UTC, а проверку локализованного вывода делайте на уровне приложения — в 2026 году это стандарт, но ошибки в триггерах, которые конвертируют время, встречаются в 30% проектов.
- Проверка погранзначений: для числовых полей тестируйте MAXINT+1, для строк — вставку NULL в NOT NULL-поле, для дат — 29 февраля в невисокосный год.
- Тестирование индексов на уникальность: создайте индекс с условием (WHERE status = ‘active’) — это частичный индекс, который обходят 70% разработчиков при написании тестов.
Отдельная тема — тестирование работы с NULL. В SQL NULL не равен NULL, и это ломает условия WHERE value NOT IN (SELECT …). Тест должен включать сценарий, когда в подзапросе есть NULL — в этом случае весь внешний запрос вернёт пустой набор. Это не баг запроса, а особенность логики, которую проверяют только профи.
Схема базы данных и миграции: как не развалить прод
Самая дорогая ошибка — миграция, которая удаляет столбец, используемый в кэше приложения. Даже если все тесты проходят, на проде начнутся ошибки из-за кэшированных данных. Решение: тестировать миграции на копии прода с включённым кэшем. Используйте инструменты вроде Flyway или Liquibase с обратной совместимостью — откат миграции должен быть протестирован до перехода на новый код. Ещё один нюанс: переименование таблицы в PostgreSQL блокирует все запросы на чтение — это может привести к простою. Тест на производительность должен включать замер времени блокировки DDL-операций.
- Тестирование индексов: добавляйте индекс через CONCURRENTLY (PostgreSQL) — это не блокирует запись, но в тестовой среде проверьте, что индекс строится без фантомных измерений.
- Семантические тесты схемы: проверьте, что длина поля VARCHAR(50) реально обрезает строку в 100 символов без сбоя — некоторые БД обрезают молча, другие выдают ошибку.
- Миграция с данными: если изменяете тип столбца (например, INT на BIGINT), тест должен гарантировать, что все существующие значения укладываются в новый диапазон без переполнения.
И наконец, тестирование репликации. В распределённых системах задержка реплик может достигать нескольких секунд. Если ваше приложение читает с реплики, а пишет на мастер, то сразу после записи чтение может вернуть старые данные. Тест must check: установите синхронную репликацию (synchronous_commit = on в PostgreSQL) — это снизит производительность на 30%, но предотвратит потерю данных. Или используйте кэш с версионированием.
Безопасность базы данных: три слоя защиты, которые обходят новички
Первый слой — SQL-инъекции. В 2026 году это всё ещё актуально из-за динамических запросов в отчётах. Профессионалы тестируют не только строковые параметры, но и числовые, и даты — инъекция может быть через ORD BY, UNION, или даже через комментарии (/*…*/). Второй слой — права доступа. На практике часто на тестовых серверах дают права dbo (или superuser), а на проде — нет. Тест должен включать попытку SELECT из другой схемы или DROP таблицы с ограниченным пользователем. Третий слой — аудит. Проверьте, что логируются все опасные операции: GRANT, REVOKE, CREATE USER. В PostgreSQL используйте pgAudit, в SQL Server — серверную трассировку.
В нашей платформе для обучения веб-разработке и дизайну мы выделили курс «Тестирование баз данных» с акцентом на эти грабли. Студенты проходят реальные кейсы: имитация взлома через UNION, тест deadlock на VACUUM в PostgreSQL и проверка консистентности после параллельного INSERT. Это не теория — вы пишете тесты, которые сразу выявляют проблемы, с которыми сталкиваются разработчики уровня Middle и Senior. Вы получите чек-лист из 50+ проверок, которые внедряются в CI/CD за один день.
Хотите перестать бояться падения БД на проде? Запишитесь на полный курс по нашему адресу — первые три урока бесплатно с доступом к тренажёру, где можно запустить собственный экземпляр PostgreSQL и пройти 20 тестов на логику блокировок. Всего за 2 недели вы научитесь отлавливать проблемы, которые упускают 80% разработчиков.
Добавлено: 23.04.2026
