Что лучше использовать для создания связей в базе данных?

Я разрабатываю API и столкнулся с выбором метода для работы со связями между таблицами: стоит ли использовать SQL-запросы или обрабатывать все через код с множественными запросами? <br/><br/> У меня есть таблица Pool, в которой содержатся холдеры (таблица Holders). Когда я выполняю запрос к /api/pool/getAll/, мне нужно получать количество холдеров для конкретного Pool, а также все поля записи Pool. <br/><br/> Кроме того, в Pool есть поле userId, указывающее на идентификатор пользователя, создавшего запись. Здесь возникает вопрос, что целесообразнее: сделать один SQL-запрос для получения всей информации или создать отдельный метод для извлечения данных о пользователе по userId? <br/><br/> Пример ответа API: <br/><pre><code>{
            "ID": 1,
            "title": "NOT",
            "rewardPool": "Reward pool",
            "logo": "not_logo",
            "createTime": 1734874558,
            "userId": 1041770840, 
            "creatorName": "vitalya_genius", // Извлекается из таблицы users по полю userId из таблицы Pool
            "creatorAvatar": "123", // Извлекается из таблицы users по полю userId из таблицы Pool
            "holdersCount": 1 // Извлекается из таблицы holders, где poolId = ID из таблицы Pool
        },</code></pre><br/><br/> Я также привожу пример двух методов, которые переписал с использованием SQL: <br/><pre><code class="php">public function getNew(): array
    {
        try {
            $sql = "SELECT p.*, u.name AS creatorName, u.avatar AS creatorAvatar,
                   (SELECT COUNT(*) FROM holders h WHERE h.poolId = p.ID) AS holdersCount
            FROM pool p
            LEFT JOIN users u ON p.userId = u.id
            ORDER BY p.createTime ASC
            LIMIT 50";

            $stmt = $this-&gt;pdo-&gt;prepare($sql);
            $stmt-&gt;ex
  • 22 декабря 2024 г. 16:23
Ответы на вопрос 2
При разработке API и организации взаимодействия с базой данных важно соблюдать баланс между производительностью и удобством использования. По вашему вопросу о том, использовать ли SQL-запросы для получения связанных данных или обрабатывать это через многократные запросы, можно выделить несколько ключевых моментов.

### 1. Использование SQL-запросов:

**Преимущества:**
- **Производительность:** Сокращает количество запросов к базе данных, что может значительно улучшить производительность, особенно в случае больших объемов данных.
- **Простота:** Один запрос к базе данных может вернуть всю нужную информацию, что упрощает обработку данных на уровне API.
- **Оптимизация:** SQL позволяет использовать `JOIN` и подзапросы, чтобы извлекать связанные данные в одном запросе, что может быть оптимально выполнено базой данных.

**Недостатки:**
- **Сложность запросов:** Если в будущем потребуется изменять структуру или логику данных (например, добавлять новые связи), запросы могут стать сложными и сложными для понимания.
- **Отладка:** Иногда более сложные запросы труднее отлаживать и анализировать.

### 2. Множественные запросы через код:

**Преимущества:**
- **Читаемость и поддержка:** Запросы могут быть проще и легче читать/поддерживать, особенно если у вас есть бизнес-логика, зависящая от результатов.
- **Гибкость:** Легче изменять отдельные запросы или добавлять логику обработки данных.

**Недостатки:**
- **Производительность:** Большое количество запросов может увеличить нагрузку на базу данных и замедлить работу API, особенно при высоком трафике.
- **Усложненная обработка данных:** Вам может потребоваться сложная логика для объединения результатов из разных запросов.

### Рекомендации:

1. **Комбинированный подход:** Для первоначальной загрузки данных лучше использовать один сложный SQL-запрос с `JOIN`, чтобы сразу получить нужную информацию о `Pool`, числе холдеров и данных пользователя. Это минимизирует количество запросов и повысит производительность.

2. **Индивидуальные запросы для специфических операций:** Если в будущем вам потребуется извлечь только определенные данные (например, информацию только о пользователе), вы можете создать отдельные методы для этого. Это позволит вам избежать излишней нагрузки на базу данных в случае, если полная информация не нужна.

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

### Пример запроса:

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

Пример:

```sql
SELECT p.*, 
       u.name AS creatorName, 
       u.avatar AS creatorAvatar,
       (SELECT COUNT(*) FROM holders h WHERE h.poolId = p.ID) AS holdersCount
FROM pool p
LEFT JOIN users u ON p.userId = u.id
ORDER BY p.createTime ASC
LIMIT 50;
```

Этот запрос является хорошим примером и будет эффективно выполняться, если индексы на поля `id` и `userId` установлены. 

### Заключение:

Таким образом, подход с одним сложным запросом для получения всех данных сразу — это в большинстве случаев предпочтительный вариант, особенно при обращении к данным, которые часто используются вместе. Если ваше приложение будет развиваться, и появится необходимость в гибкости запроса, вы всегда сможете адаптировать подход, используя отдельные методы для специфических задач.
Ну разумеется, что в общем случае через SQL-запросы. Они для того и придуманы. <br/> Но есть нюансы, иногда связанные данные приходится доставать другими методами. <br/> Например, чтобы не делать 500 отдельных запросов, берутся id нужных записей и выбираются одним запросом через where in() <br/> <br/> Кстати, лучше всё-тиаки разделить код на модели и контроллеры. SQL убрать в модели, а в контроллерах оставить только вот это вот if ($pools) {
Похожие вопросы