Какие способы выборки данных из базы данных вы знаете?

«Какие способы выборки данных из базы данных вы знаете?» — вопрос из категории Базы данных, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В разработке на PHP, особенно с фреймворками вроде Symfony/Laravel, выборка данных из БД осуществляется на разных уровнях абстракции. Вот основные подходы:

1. Нативный SQL (с использованием PDO): Прямое выполнение SQL-запросов. Дает максимальный контроль и производительность для сложных запросов.

$stmt = $pdo->prepare("SELECT id, name, email FROM users WHERE active = :active AND created_at > :date");
$stmt->execute(['active' => 1, 'date' => '2024-01-01']);
$users = $stmt->fetchAll(PDO::FETCH_ASSOC); // или fetch() для одной строки

2. Query Builder (Построитель запросов): Объектно-ориентированный API для построения SQL-запросов. Безопаснее и гибче, чем конкатенация строк.

// Пример с Doctrine DBAL (Symfony)
$queryBuilder = $connection->createQueryBuilder();
$users = $queryBuilder
    ->select('u.id', 'u.name', 'u.email')
    ->from('users', 'u')
    ->where('u.active = :active')
    ->andWhere('u.created_at > :date')
    ->setParameter('active', 1)
    ->setParameter('date', '2024-01-01')
    ->executeQuery()
    ->fetchAllAssociative();

3. ORM (Object-Relational Mapping, например, Doctrine ORM): Работа с данными как с объектами. Самый высокоуровневый подход.

  • Методы репозитория:
    $userRepository = $entityManager->getRepository(User::class);
    $user = $userRepository->find(123); // По первичному ключу
    $activeUsers = $userRepository->findBy(['active' => true]); // По простым критериям
  • DQL (Doctrine Query Language) или QueryBuilder Doctrine ORM: Для сложных запросов с объединениями.
    $query = $entityManager->createQuery(
        'SELECT u, p FROM AppEntityUser u JOIN u.posts p WHERE u.active = :active ORDER BY u.name'
    )->setParameter('active', 1);
    $users = $query->getResult(); // Возвращает массив объектов User с заполненной коллекцией posts

4. «Жадная» (EAGER) vs «Ленивая» (LAZY) загрузка:

  • Ленивая (по умолчанию в Doctrine): Связанные сущности (например, посты пользователя) загружаются только при первом обращении к ним. Может привести к проблеме N+1 запроса.
  • Жадная: Связанные сущности загружаются сразу в основном запросе (через JOIN). Задается в аннотации @ORMManyToOne(fetch="EAGER") или в DQL/QueryBuilder явным JOIN и выборкой.

Критерии выбора:

  • ORM (Doctrine) — для основной бизнес-логики, где удобна работа с объектами.
  • Query Builder (DBAL) — для сложных отчетов или административных страниц, где ORM может быть неэффективен.
  • Нативный SQL — для крайне специфичных или оптимизированных запросов, которые сложно выразить через ORM/Query Builder.