Этот запрос занимает 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 |
Какой идеальный формат для публикации схемы здесь?
Почему мой вопрос был отклонен?
Иногда StackOverflow - не самое гостеприимное место. Для схемы обычно достаточно команды «CREATE TABLE», чтобы поделиться информацией о таблицах.
@ m47730 теперь добавил информацию о таблице. Извините за задержку, был в отпуске.






Что вы будете делать с 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, и запрос выполняется очень быстро.
И мой ответ - «не делайте групповое максимальное сюда».
Пожалуйста, проверьте внимательно! Я только сделал небольшой тест
С моей точки зрения, подзапрос - это просто перебор в этом запросе (так что производительность ужасна):
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 порядок был неправильным (DESC вместо ASC), и теперь выведите все поля вашего исходного запроса плюс MIN (вы не можете избавиться от этого поля, просто проигнорируйте его в приложении). Не могли бы вы попробовать сейчас?
Мне нравится твой подход. Одна вещь, которой сейчас не хватает (кажется), - это null, когда вы не можете найти данные версии.
@ yi1 я изменил запрос, поскольку вы указываете, что нулевые значения были исключены. Если у вас есть другие проблемы, поделитесь некоторыми данными, довольно сложно вставить случайные данные и убедиться, что запрос правильный.
Очень круто @ m47730. Выходные данные вашего запроса в точности совпадают с моим исходным, время выполнения по всей базе данных (326 080 результирующих строк) было одинаковым как для вашего запроса, так и для моего исходного (оба 39-40 секунд). Я думаю, что это может быть связано с предложенным Риком-Джеймсом индексом, но я не уверен.
@ Yi1, рад быть полезным. В запросе участвуют поля: Instance_UID и Create_DateTime (для обеих таблиц) и Alert_UID (поэтому предложение Рика Джеймса улучшено лишь частично). Уловка заключается в том, чтобы избавиться от подзапроса: помните, что подзапрос - это запрос, который ожидает результата другого запроса, поэтому, если в таблице много строк, как в вашем случае, время ожидания много. Я не понимаю, но вы говорите, что ваш запрос с подзапросом работает так же, как мой с соединением?
на мой взгляд? Прекратите использовать подзапросы. Я не знаю, возможно ли это в вашем случае, вам нужно также поделиться своей схемой db, по крайней мере, из задействованных таблиц