Как оптимизировать MYSQL Запрос с медленным Order By - PullRequest
3 голосов
/ 20 марта 2020

Я пытаюсь оптимизировать мой MYSQL запрос. У меня есть только 2 тыс. Строк в базе данных, однако запрос как таковой занимает почти 1,5-2 секунды. Из-за других запросов, выполняемых в приложении Laravel, средняя загрузка страницы с этим запросом занимает слишком много времени для хорошего взаимодействия с пользователем.

Когда я удаляю заказ на, запрос занимает всего 0,03 секунды.

select * 
from `companies` 
     left join `model_has_status` on `companies`.`id` = `model_has_status`.`company_id` 
     left join `statuses` on `model_has_status`.`status_id` = `statuses`.`id`
where `model_has_status`.`status_id` = (select `status_id` 
                                        from `model_has_status` 
                                        where `company_id` = `companies`.`id` 
                                        order by `created_at` desc 
                                       limit 1) 
       and `companies`.`deleted_at` is null 
order by companies.`active_name` asc 
limit 30 offset 0

Mysql объяснение имеет следующий вывод: screenshot of the MYSQL explain

Я попытался добавить индекс companies.active_name. Однако это было безрезультатно. Кто может дать мне указатель, что оптимизировать?

Для завершения это запрос Laravel, который я выполняю из приложения:

$companies = QueryBuilder::for(Company::class)
            ->leftjoin('model_has_status', 'companies.id', 'model_has_status.company_id')
            ->leftjoin('statuses', 'model_has_status.status_id', 'statuses.id')
            ->allowedFilters([
                AllowedFilter::custom('status', new FilterCompanyStatus()),
            ])
            ->where('model_has_status.status_id', function ($query) {
                $query->select('status_id')
                    ->from('model_has_status')
                    ->whereColumn('company_id', 'companies.id')
                    ->orderByDesc('created_at')
                    ->limit(1);
            })
            ->defaultSort('active_name')
            ->paginate(30);

1 Ответ

1 голос
/ 21 марта 2020

Благодаря комментариям я провел еще некоторое исследование внутренней работы базы данных. Мне удалось оптимизировать результаты запроса с 1,8 секунды в среднем до 0,05 секунды!

Запрос вызвал три разные таблицы:

-Companies
*id
*active_name

-Model_has_status
*company_id
*status_id
*created_at

-Status
*id
*name

В исходном вопросе я добавил индекс только к companies.active_name. Это не дало никакого улучшения скорости вообще. Однако когда я добавил индексы для всех упомянутых полей, запрос значительно улучшился.

Просто чтобы завершить, я просто выполните следующие Laravel миграции для добавления индексов.

Schema::table('companies', function (Blueprint $table) {
            $table->index('active_name');
        });

        Schema::table('model_has_status', function (Blueprint $table) {
            $table->index('status_id');
            $table->index('company_id');
            $table->index('created_at');
        });

        Schema::table('statuses', function (Blueprint $table) {
            $table->index('id');
        });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...