MySQL RDS производительность функций агрегирования - PullRequest
0 голосов
/ 23 февраля 2020

У нас есть запрос, который выполняет некоторое агрегирование по одному столбцу. Фильтрация данных кажется довольно быстрой, но агрегация занимает слишком много времени.

Этот запрос возвращает ~ 1,5 миллиона строк. Он работает в течение 0,6 секунд (если мы хотим вернуть данные клиенту, это займет ~ 2 минуты - способ, которым мы протестировали это с помощью библиотеки py mysql python. Мы использовали небуферизованную курсор, поэтому мы можем различить guish между временем выполнения запроса и временем выборки):

SELECT *
FROM t_data t1
      WHERE (t1.to_date = '2019-03-20')
       AND (t1.period = 30)
       AND (label IN ('aa','bb') )
       AND ( id IN (
                SELECT id
                FROM t_location_data
                WHERE (to_date = '2019-03-20') AND (period = 30)
                  AND ( country = 'Narniya'  ) ) )

Но если мы запустим этот запрос:

SELECT  MAX(val) val_max,
        AVG(val) val_avg,
        MIN(val) val_min
FROM t_data t1
      WHERE (t1.to_date = '2019-03-20')
       AND (t1.period = 30)
       AND (label IN ('aa','bb') )
       AND ( id IN (
                SELECT id
                FROM t_location_data
                WHERE (to_date = '2019-03-20') AND (period = 30)
                  AND ( country = 'Narniya'  ) ) )

Мы увидим, что время выполнения запроса занимает 40 секунд, а время получения результатов в этом случае, очевидно, меньше секунды.

Помогите ли вы с этой ужасной производительностью функций агрегирования над RDS Aurora? Почему вычисление Max Min и Avergae на 1,5 миллиона строк занимает так много времени (при сравнении с Python для тех же чисел вычисление занимает менее 1 секунды ..)

ПРИМЕЧАНИЕ. Мы добавили случайное число к каждому выбору чтобы убедиться, что мы не получаем кэшированные значения.

Мы используем Aurora RDS:
1 экземпляр db.r5.large (2 vCPU + 16 ГБ ОЗУ) MySQL Версия двигателя: 5.6 .10a

Создать таблицу:

Create Table: CREATE TABLE `t_data` (
  `id` varchar(256) DEFAULT NULL,
  `val2` int(11) DEFAULT NULL,
  `val3` int(11) DEFAULT NULL,
  `val` int(11) DEFAULT NULL,
  `val4` int(11) DEFAULT NULL,
  `tags` varchar(256) DEFAULT NULL,
  `val7` int(11) DEFAULT NULL,
  `label` varchar(32) DEFAULT NULL,
  `val5` varchar(64) DEFAULT NULL,
  `val6` int(11) DEFAULT NULL,
  `period` int(11) DEFAULT NULL,
  `to_date` varchar(64) DEFAULT NULL,
  `data_line_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`data_line_id`),
  UNIQUE KEY `id_data` (`to_date`,`period`,`id`),
  KEY `index1` (`to_date`,`period`,`id`),
  KEY `index3` (`to_date`,`period`,`label`)
) ENGINE=InnoDB AUTO_INCREMENT=218620560 DEFAULT CHARSET=latin1

Create Table: CREATE TABLE `t_location_data` (
  `id` varchar(256) DEFAULT NULL,
  `country` varchar(256) DEFAULT NULL,
  `state` varchar(256) DEFAULT NULL,
  `city` varchar(256) DEFAULT NULL,
  `latitude` float DEFAULT NULL,
  `longitude` float DEFAULT NULL,
  `val8` int(11) DEFAULT NULL,
  `val9` tinyint(1) DEFAULT NULL,
  `period` int(11) DEFAULT NULL,
  `to_date` varchar(64) DEFAULT NULL,
  `location_line_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`location_line_id`),
  UNIQUE KEY `id_location_data` (`to_date`,`period`,`id`,`latitude`,`longitude`),
  KEY `index1` (`to_date`,`period`,`id`,`country`),
  KEY `index2` (`country`,`state`,`city`),
  KEY `index3` (`to_date`,`period`,`country`,`state`)
) ENGINE=InnoDB AUTO_INCREMENT=315944737 DEFAULT CHARSET=latin1

Параметры:

@@innodb_buffer_pool_size/1024/1024/1024:  7.7900
@@innodb_buffer_pool_instances:            8

ОБНОВЛЕНИЕ: Добавление индекса val (например, Предложение @ rick-james) значительно улучшило запрос (заняло ~ 2 секунды) , только если я удалил условие AND ( id IN (SELECT id FROM t_location_data... Если я оставлю его, запрос будет выполняться примерно на ~ 25 секунд ... лучше, чем раньше, но все еще не хорошо ..

1 Ответ

1 голос
/ 23 февраля 2020

Необходимые индексы:

t_data:  INDEX(period, to_date, label, val)
t_data:  INDEX(period, label, to_date, val)
t_location_data:  INDEX(period, country, to_date, id)

Кроме того, измените с медленного IN ( SELECT ... ) на JOIN:

FROM t_data AS d
JOIN t_location_data AS ld USING(id)
WHERE ...

Еще лучше, поскольку таблицы 1: 1 ( это правильно?), объедините таблицы, чтобы исключить JOIN. Если id не является PRIMARY KEY в каждой таблице, вам действительно необходимо предоставить SHOW CREATE TABLE и изменить имя (я).

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