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

По-умолчанию все данные получаемые через фасад DB возвращаются в виде объектов, массива объектов или коллекции объектов, что может до 10 раз увеличивать потребление памяти, по сравнению с обычными массивами. И это всё в добавок к тому, что сам PHP хранит данные в памяти самым расточительным образом!

Если ваше приложение за 1 запрос селектит не более 10-15 записей, то беспокоится на этот счёт не стоит. Однако, для приложений обрабатывающих за запрос миллионы записей — стоит задуматься об оптимизации.

К сожалению, большинство интернет-пользователей в качестве решения предлагают полученную коллекцию объектов конвертировать в массив с помощью метода toArray(), что приводит к ещё большему потреблению памяти.

Гораздо эффективным решением будет замена fetchMode библиотеки PDO с FETCH_OBJ на что-то более щадящее, например, FETCH_ASSOC.

Определено это в файле vendor/laravel/framework/src/Illuminate/Database/Connection.php

/**
     * The default fetch mode of the connection.
     *
     * @var int
     */
    protected $fetchMode = PDO::FETCH_OBJ;

Однако, править это напрямую в файле из папки с вендорами будет весьма тщетно, т.к. апдейт пакетов композера с высокой вероятностью обновит этот файл и изменения будут потеряны.

Одним из возможных решений данной ситуации будет написания обработчика в файле app/Providers/EventServiceProvider.php. Допишите в код функции \App\Providers\EventServiceProvider::boot

Event::listen(StatementPrepared::class, function ($event) {
    $event->statement->setFetchMode(\PDO::FETCH_ASSOC);
});

Вместо PDO::FETCH_ASSOC укажите любой другой вид представления данных из БД.

Говорят, что в Laravel 5.3 и младше этим можно было управлять гораздо проще, но, возможно, менее правильно:

DB::connection('db')->setFetchMode(PDO::FETCH_ASSOC);

1 Comment

Egor Gruzdev · 2018-08-09 at 16:52

Коллеги, а есть ли ссылка на материал почему в Laravel был выбран именно FETCH_OBJ?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *