Эффективность вызова базы данных Codeigniter

#mysql #performance #codeigniter

#mysql #Производительность #codeigniter

Вопрос:

Это вопрос эффективности / наилучшей практики. Надеюсь получить некоторую обратную связь о производительности. Приветствуется любой совет.

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

Я создал несколько таблиц связей: Brands_Products Products_Colors Products_Images Products_Sheets

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

Во внешнем интерфейсе я сортирую по брендам и категориям.

Я думаю, что теперь это касается предыстории части эффективности. Я предполагаю, что мой вопрос относится в основном к погоде, было бы лучше использовать объединения или выполнять отдельные вызовы для возврата отдельных частей каждого элемента (цвета, изображения и т.д.)

То, что я в настоящее время закодировал, работает и сортируется нормально, но я думаю, что смогу улучшить производительность, поскольку для возврата запроса требуется некоторое время. Прямо сейчас он возвращает около 45 элементов. Вот моя первая функция, она собирает все продукты и их информацию.

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

 public function all()
    {
        $q = $this->db
                    ->select('*')
                    ->from('Products')
                    ->join('Brands_Products', 'Brands_Products.product_id = Products.id')
                    ->join('Brands', 'Brands.id = Brands_Products.brand_id')
                    ->get();

        foreach($q->result() as $row)
        {
            // Set Regular Data
            $data['Id'] = $row->product_id;
            $data['Name'] = $row->product_name;
            $data['Description'] = $row->description;
            $data['Brand'] = $row->brand_name;
            $data['Category'] = $this->categories($row->product_id);
            $data['Product_Images'] = $this->product_images($row->product_id);
            $data['Product_Installs'] = $this->product_installs($row->product_id);
            $data['Slug'] = $row->slug;


            // Set new item in return object with created data
            $r[] = (object)$data;
        }


        return $r;
    }
  

Вот пример одной из функций, используемых для получения отдельных частей.

 private function product_installs($id)
    {
        // Select Install Images 
        $install_images = $this->db
                  ->select('*')
                  ->where('product_id', $id)
                  ->from('Products_Installs')
                  ->join('Files', 'Files.id = Products_Installs.file_id')
                  ->get();

        // Add categories to category object
        foreach($install_images->result() as $pImage)
        {
            $data[] = array(
                        'id' => $pImage->file_id, 
                        'src' => $pImage->src,
                        'title' => $pImage->title,
                        'alt' => $pImage->alt
                        );
        }

        // Make sure data exists
        if(!isset($data))
        {
            $data = array();
        }

        return $data;
    } 
  

Итак, опять же, на самом деле просто ищу совет о том, какой способ сделать это наиболее эффективным и наилучшим. Я действительно ценю любой совет или информацию.

Ответ №1:

Я думаю, что ваш подход правильный. Есть только пара вариантов: 1) сначала загрузите свой список продуктов, затем выполните цикл и загрузите необходимые данные для каждой строки продукта. 2) сначала создайте большое объединение для всех таблиц, затем выполните цикл (возможно, массивный) декартова произведения. Второе может оказаться довольно некрасивым для анализа. Например, если у вас есть продукт A и продукт B, и продукт A имеет Install 1, Install 2, Install 3, а продукт B имеет Install 1 и Install 2, то в результате получается продукт A Install 1, Продукт A Install 2, Продукт A Install 3, Продукт B Install 1, Продукт B Install 2

Теперь добавьте свои изображения и категории в объединение, и оно может стать огромным.

Я не уверен, каковы размеры ваших таблиц, но возврат 45 строк не должен занять много времени. Очевидная вещь, которую необходимо обеспечить (и вы, вероятно, уже это сделали), заключается в том, что product_id индексируется во всех таблицах, а также в ваших таблицах brands_products и других. В противном случае вы выполните сканирование таблицы.

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

Кстати, по какой причине вы преобразуете свой массив в object

 $r[] = (object)$data;
  

Кроме того, во второй функции вы можете просто добавить

 $data = array();
  

перед началом, вместо

 // Make sure data exists
if(!isset($data))
{
    $data = array();
} 
  

Комментарии:

1. Полагаю, вы правы, я вызываю все данные, когда в этом нет необходимости, не уверен, почему это вылетело у меня из головы. Я использовал свой текущий подход, чтобы избежать именно того, что вы описали выше, но я не был уверен, вызывал ли я большую разницу в производительности, делая это. Я преобразую его в объект, чтобы во внешнем интерфейсе я мог использовать -> синтаксис для всего. вместо -> иногда и array[‘key’] в других случаях. спасибо за совет, я ценю, что вы нашли время.

2. всегда пожалуйста. Пара других улучшений, которые вы, возможно, захотите рассмотреть: $ q-> result() в вашей первой функции уже возвращает массив объектов. Вы преобразуете каждый из них в массив, а затем обратно в объект. 1) Если вы настаиваете на изменении имен столбцов из базы данных на то, что видит php, хорошо. (имеется в виду идентификатор против product_id, имя против product_name). в противном случае просто повторите $ q-> result() и все готово. 2) пропустите создание массива и перейдите сразу к объекту. $data = новый стандартный класс(); $data-> id = $row-> product_id и т. Д

3. Спасибо, я исправлю это вместо того, чтобы конвертировать туда и обратно. Причина, по которой я меняю некоторые имена, в том, что кто-то другой обрабатывает часть интерфейса, хотел сделать это как можно проще для их понимания.

Ответ №2:

Вы можете попробовать это:

  1. Запрашивать все продукты
  2. Получите все идентификаторы продукта с шага 1
  3. Запрашивайте все установочные образы с идентификатором продукта с шага 2, отсортированные по идентификатору продукта
  4. Выполните итерацию по продуктам с шага 1 и добавьте результаты с шага 3

Это переводит вас с 46 запросов (для 45 продуктов) на 2 запроса, без каких-либо дополнительных объединений.

Вы также можете использовать кэширование запросов CodeIgniter для еще большего повышения производительности, если стоит потратить время на написание кода для сброса кэша при обновлении данных.

Выполнение большего объема работы на PHP, как правило, лучше, чем выполнение работы в MySQL с точки зрения масштабируемости. Вы можете легко масштабировать PHP с помощью балансировщиков нагрузки и веб-серверов. Масштабировать MySQL не так просто из-за проблем с параллелизмом.

Комментарии:

1. Я планирую интегрировать некоторое кэширование, но еще не добрался до этого, я все еще хотел убедиться, что я не был полностью эффективен в том, как я обращался к базе данных несколько раз. Спасибо за обратную связь, я немного поиграю с этим и посмотрю, что я могу придумать.

2. Неэффективность заключается в том, что способ, которым вы это настроили, не масштабируется. У вас всегда есть n 1 запросов для n продуктов против 2 запросов для n продуктов. Даже без кэширования метод 2 запросов лучше.