Что быстрее отработает: один большой или множество маленьких запросов к базе данных?

Ответ

В большинстве случаев один большой запрос выполняется быстрее множества маленьких. Основная причина — сокращение сетевых издержек и накладных расходов СУБД.

Преимущества одного запроса:

  • Снижение сетевого латентности: Каждый запрос требует передачи данных туда и обратно между приложением и БД.
  • Меньше накладных расходов СУБД: Парсинг, оптимизация и выполнение плана запроса происходят один раз.
  • Решение проблемы N+1: Классическая антипаттерн, когда для получения связанных данных выполняется множество дополнительных запросов.

Пример (PHP с PDO):

// Медленно: N+1 запросов
$userIds = [1, 2, 3, 4, 5];
$users = [];
foreach ($userIds as $id) {
    $stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
    $stmt->execute([$id]);
    $users[] = $stmt->fetch(PDO::FETCH_ASSOC);
}

// Быстро: один запрос с IN
$placeholders = str_repeat('?,', count($userIds) - 1) . '?';
$stmt = $pdo->prepare("SELECT * FROM users WHERE id IN ($placeholders)");
$stmt->execute($userIds);
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);

Когда множество маленьких запросов может быть оправдано:

  1. Пагинация: Загрузка данных постранично, чтобы не выгружать гигабайты за раз.
  2. Ленивая загрузка (Lazy Loading): Данные подгружаются только когда они действительно нужны.
  3. Сложные агрегации по большим таблицам: Один тяжелый аналитический запрос может блокировать ресурсы, тогда лучше разбить его на части.

Ответ 18+ 🔞

Давай разберём эту тему, а то некоторые до сих пор не врубаются, как будто на дворе 2002-й год. Слушай сюда, всё просто, как три копейки.

Представь, что твоё приложение — это я, а база данных — это шаурмичная в трёх кварталах. Каждый маленький запрос — это я бегу туда, кричу «дай один лаваш!», получаю его и несу обратно. А потом опять бегу, потому что коллега тоже захотел. Овердохуища беготни получается, я устаю, они злятся, время летит к ебеням.

А теперь умный подход: я звоню в ту же шаурмичную и говорю: «Мужик, собери мне пять лавашей, я через десять минут приеду и заберу всё разом». Один звонок, одна поездка — и у всей команды обед. Вот и вся магия, ёпта.

В чём конкретно выгода, спросишь?

  • Сеть не грузишь по-чёрному. Каждая твоя пробежка туда-обратно — это латентность, пинг, время, которое можно было потратить на что-то полезное, а не на ожидание.
  • Базу не дрочишь попусту. Каждый раз, когда ты прибегаешь со своим кривым SELECT * FROM users WHERE id = 1, СУБД должна твой запрос распарсить, придумать, как его выполнить (составить план), и только потом выполнить. А если ты принёс один запрос на пять юзеров — она эту манду с ушами проделала всего один раз. Экономия — хуй с горы.
  • Решаешь проблему N+1. Это классика, пидарас шерстяной. Получил N записей, а потом в цикле для каждой делаешь ещё по запросу за связанными данными. В итоге вместо одного запроса у тебя N+1. Это пиздец как неэффективно, доверия к такому коду — ноль ебать.

Смотри, как это выглядит в коде:

// Тупой способ (N+1 запрос). Выглядит как работа, а на деле — распиздяйство.
$userIds = [1, 2, 3, 4, 5];
$users = [];
foreach ($userIds as $id) {
    $stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
    $stmt->execute([$id]);
    $users[] = $stmt->fetch(PDO::FETCH_ASSOC); // Бегаю за каждым лавашом отдельно
}

// Умный способ (1 запрос). Сделал дело — гуляй смело.
$placeholders = str_repeat('?,', count($userIds) - 1) . '?';
$stmt = $pdo->prepare("SELECT * FROM users WHERE id IN ($placeholders)");
$stmt->execute($userIds); // Привёз всё разом
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);

Чувствуешь разницу? В первом случае ты как мартышлюшка на банановой плантации — туда-сюда, туда-сюда. Во втором — пришёл, нагрузил полную корзину и довольный ушёл.

Но и тут есть свои «а чо, так можно было?» моменты. Иногда много маленьких запросов — не тупость, а необходимость.

  1. Пагинация. Ты же не будешь выгружать все 10 миллионов записей разом? Сам от себя охуеешь, когда память кончится. Берёшь по страничке, по 100 штук — и все довольны.
  2. Ленивая загрузка. Зачем тебе сразу фотки, аватары и история комментариев пользователя, если ты на главной странице только логины выводишь? Подгрузил основное, а остальное — потом, когда пользователь в профиль зашёл. Хитрая жопа, но работает.
  3. Очень сложные отчёты по терабайтам данных. Один запрос может впендюрить базу так, что все остальные будут ждать, пока он не кончит. Иногда лучше разбить его на несколько этапов, как слона — чтоб не подавиться.

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