Как создать тестовую среду для выполнения запросов PostgreSQL?

Я решила помочь с проектом, и, хотя работа уже сделана, всё равно возникло ощущение, что реализация довольно громоздкая. Возможно, более опытные специалисты смогут предложить способы улучшения и упрощения. <br/><br/> Это для сервиса, который позволит пользователям решать задачи по SQL, конкретно в диалекте Postgres. Необходимо, чтобы пользователь мог отправить скрипт с своим запросом (с небольшими строчками CREATE/INSERT, добавляемыми в начале), после чего мы могли бы проверить результат. Процесс отправки уже реализован, но основная трудность заключается в изоляции выполнения скриптов, чтобы избежать повреждения системы и воздействия одного запроса на другой. <br/><br/> Я потратила вечер на поиски и в итоге разработала следующее решение, использующее Docker на базе Ubuntu. Вот наш Dockerfile: <br/><br/> <pre><code class="bash">DEBIAN_FRONTEND=noninteractive apt install -y postgresql
useradd pguser
mkdir /test
chown pguser /test
chown pguser /var/run/postgresql
su pguser -s /bin/bash
/usr/lib/postgresql/16/bin/initdb -D /test/db</code></pre> <br/><br/> Эта команда initdb выполняется в течение 10-20 секунд, поэтому её, вероятно, следует запускать на старте. Есть ли способы ускорить этот процесс? <br/><br/> Остальная часть выполняется каждый раз в сессии (т.е. при получении и выполнении запроса) под пользователем pguser: <br/><br/> <pre><code class="bash">/usr/lib/postgresql/16/bin/pg_ctl -D /test/db -l /dev/null start &gt;/dev/null 2&gt;&amp;1
createdb
psql -q --csv -c '...' # тут будут команды CREATE TABLE; INSERT; SELECT... на самом деле скорее всего будет выполняться из файла, не имеет значения
dropdb pguser
/usr/lib/postgresql/16/bin/pg_ctl -D /test/db stop
/usr/lib/postgresql/16/bin/pg_resetwal -D /test/db</code></pre> <br/><br/> В целом это работает, выполнение занимает около 3-5 секунд, но кажется, что директория с базой данных...
  • 14 сентября 2024 г. 5:53
Ответы на вопрос 2
Создание тестовой среды для выполнения запросов PostgreSQL с использованием Docker — это хороший подход, особенно если вам требуется изоляция выполнения запросов и безопасность. Однако, есть несколько способов оптимизировать и упростить вашу текущую реализацию.

### Оптимизации

1. **Использование многоконтейнерной архитектуры**: Вместо создания базы данных каждый раз, вы можете использовать один контейнер PostgreSQL для выполнения всех запросов. Создайте базу данных один раз и просто выполняйте SQL-команды внутри существующей базы данных, не пересоздавая её каждый раз.

2. **Предварительно созданная база данных**: Если у вас есть общий набор таблиц и данных, которые будут использоваться в тестах, вы можете предварительно создать базу данных с этими данными. Этим можно избежать затрат на создание и заполнение базы данных каждый раз.

3. **Разработка управления состоянием**: Вы можете использовать миграции на базе данных или использовать инструменты типа `Flyway` или `Liquibase` для управления схемами и данными, что значительно упростит подготовку вашей базы данных.

4. **Использование docker-compose**: С помощью `docker-compose` вы можете задать все необходимые контейнеры, включая PostgreSQL. Это упростит создание и управление контейнерами.

### Пример `docker-compose.yml`

```yml
version: '3.8'
services:
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: pguser
      POSTGRES_PASSWORD: pgpassword
      POSTGRES_DB: testdb
    volumes:
      - test_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  test_data:
```

### Выполнение запросов

Вместо повторной инициализации базы данных вы можете запускать произвольные SQL-запросы, используя CLI-клиент `psql` в контейнере:

```bash
docker exec -i <container_name> psql -U pguser -d testdb -f /path/to/your/script.sql
```

или

```bash
docker exec -i <container_name> psql -U pguser -d testdb -c "YOUR_SQL_COMMAND"
```

### Удаление данных

Если вам нужно очищать данные между запросами, вам не нужно удалять весь контейнер. Вы можете просто использовать команды для очистки таблиц или использовать изоляцию через транзакции.

Если вам необходимо полностью сбрасывать базу данных, вы можете использовать `DROP DATABASE` и `CREATE DATABASE`, но делайте это с осторожностью, чтобы не потерять важные данные, если они есть.

### Преимущества такого подхода

- **Быстродействие**: Pre-setup базы данных уменьшает время на запуск новых запросов.
- **Изоляция**: Каждый запрос не влияет на другие, если вы следите за тем, чтобы использовать разные схемы или транзакции.
- **Удобство**: Использование `docker-compose` для управления контейнерами делает вашу систему более простой в управлении и развертывании.

Этот подход даст вам больше гибкости и повысит эффективность тестовой среды для выполнения запросов PostgreSQL.
Я правильно понимаю, что вы на каждый запрос поднимаете новый контейнер с инициализацией кластера? Напрасно. 

Я бы смотрел в сторону "один пользователь (или даже запрос) - одна БД внутри постоянно работающей толстой СУБД". Ну и БД периодически ротировал с очисткой.
Похожие вопросы