Как сделать запрос в представлении MySQL быстрее?

Этот запрос занимает 1,2 секунды:

select * from alert limit 10000;

Этот запрос занимает 33,99 секунды:

select * from alert_version limit 10000;

alert_version - это представление, которое по сути представляет собой таблицу «предупреждений» с подзапросом:

select  `alert`.`Alert_UID` AS `Alert_UID`,`alert`.`Rule_Name` AS `Rule_Name`,
        `alert`.`Headline` AS `Headline`,`alert`.`Severity` AS `Severity`,
        `alert`.`Device_UID` AS `Device_UID`,`alert`.`Configuration_Set_ID` AS `Configuration_Set_ID`,
        `alert`.`Instance_UID` AS `Instance_UID`,`alert`.`Create_DateTime` AS `Create_DateTime`,
        `alert`.`Delete_DateTime` AS `Delete_DateTime`,
        ( SELECT  `version_build`.`Version`
            from  `version_build`
            where  ((`version_build`.`Instance_UID` = `alert`.`Instance_UID`)
                      and  (`version_build`.`Create_DateTime` >= `alert`.`Create_DateTime`)
                   )
            order by  `version_build`.`Create_DateTime`
            limit  1
        ) AS `version`
    from  `alert` 

Когда я запускаю EXPLAIN по этому запросу, я получаю:

+----+--------------------+---------------+------+-----------------------------------------------------------------------------------+--------------------------+---------+----------------------------+--------+------------------------------------------+
| id | select_type        | table         | type | possible_keys                                                                     | key                      | key_len | ref                        | rows   | Extra                                    |
+----+--------------------+---------------+------+-----------------------------------------------------------------------------------+--------------------------+---------+----------------------------+--------+------------------------------------------+
|  1 | PRIMARY            | alert         | ALL  | NULL                                                                              | NULL                     | NULL    | NULL                       | 301274 | NULL                                     |
|  2 | DEPENDENT SUBQUERY | version_build | ref  | uid_version_build_create,version_build_Instance_UID,version_build_Create_DateTime | uid_version_build_create | 110     | insight.alert.Instance_UID |      6 | Using where; Using index; Using filesort |
+----+--------------------+---------------+------+-----------------------------------------------------------------------------------+--------------------------+---------+----------------------------+--------+------------------------------------------+

Итак, как вы думаете, что мне нужно сделать, чтобы добиться приемлемой производительности?

Обновлено:

По запросу, добавление информации о таблице:

CREATE TABLE `alert` (
`Alert_UID` varchar(36) NOT NULL,
`Rule_Name` varchar(80) DEFAULT NULL,
`Headline` varchar(255) DEFAULT NULL,
`Severity` varchar(12) DEFAULT NULL,
`Device_UID` varchar(36) NOT NULL,
`Configuration_Set_ID` varchar(12) DEFAULT NULL,
`Instance_UID` varchar(36) NOT NULL,
`Create_DateTime` timestamp NOT NULL,
`Delete_DateTime` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`Alert_UID`),
KEY `alert_Create_DateTime` (`Alert_UID`,`Create_DateTime`),
KEY `alert_Headline` (`Headline`),
KEY `alert_Rule_Headline` (`Rule_Name`,`Headline`),
KEY `alert_Instance_UID` (`Instance_UID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |


CREATE TABLE `version_build` (
`Instance_UID` varchar(36) NOT NULL,
`Version` varchar(12) NOT NULL,
`Build` varchar(30) DEFAULT NULL,
`Create_DateTime` timestamp NOT NULL,
UNIQUE KEY `uid_version_build_create` 
(`Instance_UID`,`Version`,`Build`,`Create_DateTime`),
KEY `version_build_Instance_UID` (`Instance_UID`),
KEY `version_build_Create_DateTime` (`Create_DateTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

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

m47730 22.06.2018 16:56

Какой идеальный формат для публикации схемы здесь?

yi1 22.06.2018 17:54

Почему мой вопрос был отклонен?

yi1 22.06.2018 17:54

Иногда StackOverflow - не самое гостеприимное место. Для схемы обычно достаточно команды «CREATE TABLE», чтобы поделиться информацией о таблицах.

m47730 25.06.2018 08:44

@ m47730 теперь добавил информацию о таблице. Извините за задержку, был в отпуске.

yi1 03.07.2018 03:55
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
0
5
67
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Что вы будете делать с 10К строками? Обычно это слишком много для приложения.

Какие 10К строк вы надеетесь получить без ORDER BY? Это непредсказуемо. С ORDER BY запрос может быть еще медленнее.

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

INDEX(Instance_UID, Create_DateTime, Version)   -- in this order!

Подробнее о groupwise-max: http://mysql.rjweb.org/doc.php/groupwise_max

10К строк были всего лишь образцом. На самом деле то, что я делаю, - это вытаскивание всего вывода запроса в приложение. С простым запросом это терпимо. С информацией о подзапросе он в 33 раза длиннее, что недопустимо. Я посмотрел на ваши решения, но особого прироста производительности не получил. Как вы думаете, это типичный случай, когда просто создание таблицы alert_version и заполнение ее запланированным событием было бы лучшим решением? Таким образом, время тратится cron, и запрос выполняется очень быстро.

yi1 03.07.2018 04:04

И мой ответ - «не делайте групповое максимальное сюда».

Rick James 03.07.2018 07:01
Ответ принят как подходящий

Пожалуйста, проверьте внимательно! Я только сделал небольшой тест

С моей точки зрения, подзапрос - это просто перебор в этом запросе (так что производительность ужасна):

SELECT
`alert`.`Alert_UID` AS `Alert_UID`,
`alert`.`Rule_Name` AS `Rule_Name`,
`alert`.`Headline` AS `Headline`,
`alert`.`Severity` AS `Severity`,
`alert`.`Device_UID` AS `Device_UID`,
`alert`.`Configuration_Set_ID` AS `Configuration_Set_ID`,
`alert`.`Instance_UID` AS `Instance_UID`,
`alert`.`Create_DateTime` AS `Create_DateTime`,
`alert`.`Delete_DateTime` AS `Delete_DateTime`, 
`version_build`.`Version` AS `version`,
MIN(version_build.Create_DateTime)
FROM alert
LEFT JOIN version_build ON (alert.Instance_UID = version_build.Instance_UID
AND version_build.Create_DateTime >= alert.Create_DateTime)
GROUP BY alert.Alert_UID

Группа по не зависит от порядка, поэтому необходимо использовать MIN в поле выбора, иначе порядок будет непредсказуемым. Я не тестировал производительность, но думаю, что это часть подзапроса.

Теперь с нулевыми значениями на случай, если условие соединения не выполнено.

Результат вашего запроса - это не тот результат, который мне нужен

yi1 04.07.2018 16:12

@ yi1 порядок был неправильным (DESC вместо ASC), и теперь выведите все поля вашего исходного запроса плюс MIN (вы не можете избавиться от этого поля, просто проигнорируйте его в приложении). Не могли бы вы попробовать сейчас?

m47730 04.07.2018 16:45

Мне нравится твой подход. Одна вещь, которой сейчас не хватает (кажется), - это null, когда вы не можете найти данные версии.

yi1 05.07.2018 21:36

@ yi1 я изменил запрос, поскольку вы указываете, что нулевые значения были исключены. Если у вас есть другие проблемы, поделитесь некоторыми данными, довольно сложно вставить случайные данные и убедиться, что запрос правильный.

m47730 06.07.2018 10:02

Очень круто @ m47730. Выходные данные вашего запроса в точности совпадают с моим исходным, время выполнения по всей базе данных (326 080 результирующих строк) было одинаковым как для вашего запроса, так и для моего исходного (оба 39-40 секунд). Я думаю, что это может быть связано с предложенным Риком-Джеймсом индексом, но я не уверен.

yi1 10.07.2018 02:25

@ Yi1, рад быть полезным. В запросе участвуют поля: Instance_UID и Create_DateTime (для обеих таблиц) и Alert_UID (поэтому предложение Рика Джеймса улучшено лишь частично). Уловка заключается в том, чтобы избавиться от подзапроса: помните, что подзапрос - это запрос, который ожидает результата другого запроса, поэтому, если в таблице много строк, как в вашем случае, время ожидания много. Я не понимаю, но вы говорите, что ваш запрос с подзапросом работает так же, как мой с соединением?

m47730 10.07.2018 09:08

Другие вопросы по теме