MySql группа по оптимизации - избегайте таблицы tmp и / или сортировки файлов - PullRequest
0 голосов
/ 06 марта 2019

У меня медленный запрос, без группировки быстро (0,1-0,3 секунды), но с (требуемой) группой по продолжительности около 10-15 с.

Запрос объединяет две таблицы: события (около 50 миллионов строк) и events_locations (5 миллионов строк).

Запрос:

SELECT  `e`.`id` AS `event_id`,`e`.`time_stamp` AS `time_stamp`,`el`.`latitude` AS `latitude`,`el`.`longitude` AS `longitude`,
        `el`.`time_span` AS `extra`,`e`.`entity_id` AS `asset_name`, `el`.`other_id` AS `geozone_id`,
        `el`.`group_alias` AS `group_alias`,`e`.`event_type_id` AS `event_type_id`,
        `e`.`entity_type_id`AS `entity_type_id`, el.some_id
FROM events e
INNER JOIN events_locations el ON el.event_id = e.id
WHERE 1=1       
    AND el.other_id = '1'  
    AND time_stamp >= '2018-01-01'  
    AND time_stamp <= '2019-06-02'
GROUP BY `e`.`event_type_id` , `el`.`some_id` , `el`.`group_alias`;

Таблица событий:

CREATE TABLE `events` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `event_type_id` int(11) NOT NULL,
  `entity_type_id` int(11) NOT NULL,
  `entity_id` varchar(64) NOT NULL,
  `alias` varchar(64) NOT NULL,
  `time_stamp` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `entity_id` (`entity_id`),
  KEY `event_type_idx` (`event_type_id`),
  KEY `idx_events_time_stamp` (`time_stamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Таблица events_locations

CREATE TABLE `events_locations` (
  `event_id` bigint(20) NOT NULL,
  `latitude` double NOT NULL,
  `longitude` double NOT NULL,
  `some_id` bigint(20) DEFAULT NULL,
  `other_id` bigint(20) DEFAULT NULL,
  `time_span` bigint(20) DEFAULT NULL,
  `group_alias` varchar(64) NOT NULL,
  KEY `some_id_idx` (`some_id`),
  KEY `idx_events_group_alias` (`group_alias`),
  KEY `idx_event_id` (`event_id`),
  CONSTRAINT `fk_event_id` FOREIGN KEY (`event_id`) REFERENCES `events` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Объяснение:

+----+-------------+-------+--------+---------------------------------+---------+---------+-------------------------------------------+----------+------------------------------------------------+
| id | select_type | table | type   | possible_keys                   | key     | key_len | ref                                       | rows     | Extra                                          |
+----+-------------+-------+--------+---------------------------------+---------+---------+-------------------------------------------+----------+------------------------------------------------+
| 1  | SIMPLE      | ea    | ALL    | 'idx_event_id'                  | NULL    | NULL    | NULL                                      | 5152834  | 'Using where; Using temporary; Using filesort' |
| 1  | SIMPLE      | e     | eq_ref | 'PRIMARY,idx_events_time_stamp' | PRIMARY | '8'     | 'name.ea.event_id'                        | 1        |                                                |
+----+-------------+----------------+---------------------------------+---------+---------+-------------------------------------------+----------+------------------------------------------------+
2 rows in set (0.08 sec)

Из документа :

Временные таблицы могут быть созданы при следующих условиях:

Если есть предложение ORDER BY и другое предложение GROUP BY или если ORDER BY или GROUP BY содержит столбцы из таблиц, отличных от первой таблицы в очереди соединения, создается временная таблица.

DISTINCT в сочетании с ORDER BY может потребовать временную таблицу.

Если вы используете параметр SQL_SMALL_RESULT, MySQL использует временную таблицу в памяти, если только запрос не содержит элементов (описанных ниже), которые требуют хранения на диске.

Я уже пробовал:

  • Создать индекс по 'el. some_id, el. group_alias'
  • Уменьшите размер varchar до 20
  • Увеличить размер sort_buffer_size и read_rnd_buffer_size;

Будем весьма благодарны за любые предложения по настройке производительности!

Ответы [ 2 ]

1 голос
/ 06 марта 2019

В вашем случае events таблица имеет time_span в качестве свойства индексации.Поэтому, прежде чем объединить обе таблицы, сначала выберите необходимые записи из таблицы events для определенного диапазона дат с необходимыми подробностями.Затем присоединитесь к event_location, используя свойства отношения таблиц.

Проверьте ключевое слово MySql Explain, чтобы проверить, как вы подходите к записям таблицы.Он скажет вам, сколько строк проверено, прежде чем выбрать необходимые записи.

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

SELECT  
    `e`.`id` AS `event_id`,
    `e`.`time_stamp` AS `time_stamp`,
    `el`.`latitude` AS `latitude`,
    `el`.`longitude` AS `longitude`,
    `el`.`time_span` AS `extra`,
    `e`.`entity_id` AS `asset_name`, 
    `el`.`other_id` AS `geozone_id`,
    `el`.`group_alias` AS `group_alias`,
    `e`.`event_type_id` AS `event_type_id`,
    `e`.`entity_type_id` AS `entity_type_id`, 
    `el`.`some_id` as `some_id`
FROM 
    (select
        `id` AS `event_id`,
        `time_stamp` AS `time_stamp`,
        `entity_id` AS `asset_name`,
        `event_type_id` AS `event_type_id`,
        `entity_type_id` AS `entity_type_id`
    from
        `events` 
    WHERE
        time_stamp >= '2018-01-01'  
        AND time_stamp <= '2019-06-02'
    ) AS `e`    
    JOIN `events_locations` `el` ON `e`.`event_id` = `el`.`event_id`
WHERE     
    `el`.`other_id` = '1'      
GROUP BY 
    `e`.`event_type_id` , 
    `el`.`some_id` , 
    `el`.`group_alias`;
0 голосов
/ 13 марта 2019

Соотношение между этими таблицами составляет 1: 1, поэтому я спросил меня, зачем нужна группа, и нашел несколько дублированных строк, 200 на 50000 строк. Так или иначе, моя система вставляет дубликаты, и кто-то поместил эту группу (несколько лет назад) вместо поиска ошибки.

Итак, я отмечу это как решенное, более или менее ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...