Рубрики
Uncategorized

PHP и MySQL “Объединение данных один к одному” Лучшая практика

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

Предисловие

В процессе разработки обычно возникает множество проблем. Один на один Обработка данных. Большую часть времени мы будем получать список, а затем одна запись списка соответствует другой таблице для достижения бизнеса. Например, следующие Информация о товарах и Сведения о товарах Две таблицы. Чтобы продемонстрировать, что используются только базовые поля, фактическая разработка может быть намного сложнее. Использование подключений к базе данных в следующем демонстрационном коде PDO Обработка.

Структура таблицы

товары

int(11) Автоматическое увеличение Идентификатор первичного ключа идентификатор
варчар(100) Фирменное наименование заглавие
десятичное число(10,2) цена на сырьевые товары цена
варчар(100) Обложка продукта покрытие

goods_деталь

int(11) Автоматическое увеличение Идентификатор первичного ключа идентификатор
инт(11) Идентификатор товара идентификатор товара
варчар(5000) Знакомство с графикой и текстами товаров содержание

первичный

Честно говоря, я видел следующий код как в компании, так и в некоторых проектах с открытым исходным кодом.

$query = $db->query('select * from goods');
$result = $query->fetchAll();
// scheme 1
foreach($result as $key => $item){
    $query = $db->query('select * from goods_detail where goods_id=' . $item['id']);
    $result[$key]['goods_detail'] = $query->fetch();
}
var_dump($result);
// plan two
foreach($result as &$item){
    $query = $db->query('select * from goods_detail where goods_id=' . $item['id']);
    $item['goods_detail'] = $query->fetch();
}
unset($item);
var_dump($result);
// plan three
$result = array_map(function($item){
    $query = $db->query('select * from goods_detail where goods_id=' . $item['id']);
    $item['goods_detail'] = $query->fetch();
    return $item;
},$result);
var_dump($result);

Это самый жестокий способ, и это стоячий взгляд, и Схема 1 Кажется, что код все еще очень утомителен, не так ли? Если вы научились цитировать этот раздел, вы должны знать второе использование. Вы должны использовать ссылку для непосредственного управления исходными данными. Конечно, вам лучше не забыть, наконец, отключить пункт$. Помимо второго, мы можем использовать третий способ, array_map, который ничем не отличается от второго способа, но есть очень большая проблема: запрос базы данных. N+1 。 Из выполнения мы видим, что в дополнение к списку запросов SQL каждая запись запроса соответствует необходимости выполнения SQL, в результате чего возникают дополнительные запросы, подумайте, не сделал ли запрос. предел Ограничения. На что это было бы похоже?

Передовой

Увидев это, кто-то может подумать о другом решении: сначала запросите список, а затем извлеките его. идентификатор товара Позже используйте в запросе, а затем перейдите к списку, чтобы увидеть код.

$goods_id = array_column($result,'id');
$goods_id_str = implode(',',$goods_id);
$query = $db->query(sprintf('select * from goods_detail where goods_id in (%s)',$goods_id_str));
$goods_detail_list = $query->fetchAll();
foreach($result as &$item){
    $item['goods_detail'] = array_first($goods_detail_list,function($item1){
        return $item['id'] == $item1['goods_id'];
    });
}
unset($item);
var_dump($result);
/**
 * From Laravel
 */
if (!function_exists('value')) {
    function value($value)
    {
        return $value instanceof Closure ? $value() : $value;
    }
}
/**
 * From Laravel
 */
if (!function_exists('array_first')) {
    /**
     * @param               $array
     * @param callable|null $callback
     * @param null          $default
     * @return mixed
     */
    function array_first($array, callable $callback = null, $default = null)
    {
        if (is_null($callback)) {
            if (empty($array)) {
                return value($default);
            }

            foreach ($array as $item) {
                return $item;
            }
        }

        foreach ($array as $key => $value) {
            if (call_user_func($callback, $value, $key)) {
                return $value;
            }
        }

        return value($default);
    }
}

В этом коде мы прекрасно избежали этого. N+1 Дилемма, используемая в Запросите, затем пройдитесь по массиву, а затем используйте метод array_first для поиска и передачи в goods_detail Индексирование, хотя оно намного эффективнее первого, не является совершенным. Далее, давайте посмотрим на последнее. Для array_first вы можете ознакомиться с другой моей статьей “array_find в многомерных массивах PHP”.

Лучшие практики

$goods_detail_list_by_keys = array_column($goods_detail_list,null,'goods_id');
foreach($result as &$item){
    $item['goods_detail'] = array_key_exists($goods_detail_list_by_keys,$item['id']) ? $goods_detail_list_by_keys[$item['id']] : null ;
    // php 7.1+
    // $item['goods_detail'] = $goods_detail_list_by_keys[$item['id']] ?? null;
}
unset($item);
var_dump($result);

На этот раз мы используем две другие функции. Array_column, array_key_ существует, один за другим, на самом деле столбец array_column В официальном руководстве мы можем представить метод, который мы хотим использовать в примере № 2. Применение его здесь означает сброс. goods_деталь_лист Ключ элемента внутри находится под одним элементом. идентификатор товара 。 Мы воспользуемся им непосредственно позже. array_key_exists Судите, существует ли он, а затем выполните соответствующую обработку. Здесь мы также можем выполнить другую операцию, которая является значением по умолчанию, потому что иногда данные могут быть неверными, если их обнаружат непосредственно в интерфейсе, интерфейс не ожидал, что в этой ситуации отказоустойчивая обработка приведет к сбою интерфейсной страницы, а затем к перезаписи кода.

// In the "Advanced" section, we use the "array_first" function. The third parameter of the function can directly set the default value. We will not talk more about it, but mainly about the last one.
$goods_detail_default = [
    'content'=>'default content',
    'id'      => null,
    'goods_id'=> null,
];
foreach($result as &$item){
    $tmp = array_key_exists($goods_detail_list_by_keys,$item['id']) ? $goods_detail_list_by_keys[$item['id']] : [] ;
    // php 7.1+
    // $tmp = $goods_detail_list_by_keys[$item['id']] ?? [];
    $item['goods_detail'] = array_merge($goods_detail_default,$tmp);
}
unset($item);
var_dump($result);

Конец

Смотрите здесь, даже если он закончен, но некоторые друзья скажут, почему бы не использовать его? Левое соединение С чем иметь дело? Действительно, в процессе Отношения один к одному Много раз мы выбираем. внутреннее соединение возможно левое соединение Для обработки можно выполнить один SQL, редко используя аналогичные решения, на самом деле, в противном случае в основной фрейм работе решения по умолчанию почти одинаковы, такие как Laravel, ThinkPHP, учитывая, что будет много сценариев, например, иногда мне просто нужно принять участие в нем по требованию, или мне нужно принять решение на основе результатов моего последующего бизнеса. Не для того, чтобы загружать один к одному, но в этом случае присоединяйтесь Это кажется не очень подходящим.

Оригинал: “https://developpaper.com/php-mysql-data-association-one-to-one-best-practice/”