Рубрики
Uncategorized

Решение проблемы запроса базы данных N+1

Автор оригинала: David Wong.

требование

Таблица данных выглядит следующим образом:

Таблица отдела

|идентификатор|имя|

Таблица пользователей

|идентификатор|имя|идентификатор отдела|

Требование состоит в том, чтобы получить данные следующей структуры:

[
    {
        "id":1,
        "name":"test",
        "department_id":1,
        "department":{
            "id":1,
            "Name": "testing department"
        }
    }
]

Метод 1: Циклический запрос

  1. Запрос Списка пользователей
  2. Зациклите список пользователей, чтобы запросить соответствующую информацию об отделе
$users = $db->query('SELECT * FROM `user`');
foreach($users as &$user) {
    $users['department'] = $db->query('SELECT * FROM `department` WHERE `id` = '.$user['department_id']);
}

Время запроса этого метода составляет: 1 + N (1 список запросов, отделы запросов), который имеет самую низкую производительность и нежелателен.

Способ 2: Подключение таблиц

  1. Запрашивайте данные пользователей и подразделений через связанные таблицы
  2. Обработка возвращенных данных
$users = $db->query('SELECT * FROM `user` INNER JOIN `department` ON `department`.`id` = `user`.`department_id`');
// Manually process the returned result as a requirement structure

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

Способ 3: 1 + 1 запрос

  1. Этот метод сначала запрашивает список пользователей один раз.
  2. Удалите идентификатор отдела из списка, чтобы сформировать массив
  3. Запросите отдел на шаге 2
  4. Объединить окончательные данные

Код примерно выглядит следующим образом:

$users = $db->query('SELECT * FROM `user`');
$departmentIds =[ ];
foreach($users as $user) {
    if(!in_array($user['department_id'], $departmentIds)) {
        $departmentIds[] = $user['department_id'];
    }
}
$departments = $db->query('SELECT * FROM `department` WHERE id in ('.join(',',$department_id).')');
$map = []; // [Department ID = > Department item]
foreach($departments as $department) {
    $map[$department['id']] = $department;
}

foreach($users as $user) {
    $user['department'] = $map[$user['department_id']] ?? null;
 }

Этот метод не имеет ограничений на две таблицы и является лучшим подходом в условиях преобладающей ситуации с микросервисами.

Оригинал: “https://developpaper.com/solving-the-query-problem-of-database-n1/”