Очень медленно MySQL LeftJoin на AWS RDS, но очень быстро в других местах - PullRequest
0 голосов
/ 14 июля 2020

MySQL в PROD проходит через AWS RDS (Aurora, db.t3.small). Ультизация ресурсов по всем направлениям находится на приемлемом уровне.

Если я выполняю следующий SELECT, это почти мгновенно:

 SELECT SQL_CALC_FOUND_ROWS `submissions`.*
 FROM `cmsb_submissions` as `submissions`
 WHERE (status = '4') 
 LIMIT 15

Если я добавляю LEFTJOIN, это занимает более 15 секунд :

SELECT SQL_CALC_FOUND_ROWS `submissions`.*,
`explorer_points_earning`.`num` AS `explorer_points_earning.num`,
`explorer_points_earning`.`createdDate` AS `explorer_points_earning.createdDate`,
`explorer_points_earning`.`createdByUserNum` AS `explorer_points_earning.createdByUserNum`,
`explorer_points_earning`.`updatedDate` AS `explorer_points_earning.updatedDate`,
`explorer_points_earning`.`updatedByUserNum` AS `explorer_points_earning.updatedByUserNum`,
`explorer_points_earning`.`user` AS `explorer_points_earning.user`,
`explorer_points_earning`.`points_earned` AS `explorer_points_earning.points_earned`,
`explorer_points_earning`.`for_trail` AS `explorer_points_earning.for_trail`
FROM `cmsb_submissions` as `submissions`
LEFT JOIN `cmsb_explorer_points_earning` AS `explorer_points_earning` 
     ON submissions.num = explorer_points_earning.for_trail
    AND explorer_points_earning.user = 7
WHERE (status = '4') 
 LIMIT 15

Ни одна из таблиц не является большой:

explorer_points_earning = 17,000 records
submissions = 1,000 records 

и существуют следующие ИНДЕКСЫ:

SHOW INDEX FROM cmsb_explorer_points_earning;

'cmsb_explorer_points_earning', '0', 'PRIMARY', '1', 'num', 'A', '17155', NULL, NULL, '', 'BTREE', '', ''
'cmsb_explorer_points_earning', '1', '_auto_for_trail', '1', 'for_trail', 'A', '2450', '16', NULL, 'YES', 'BTREE', '', ''
'cmsb_explorer_points_earning', '1', '_auto_user', '1', 'user', 'A', '3431', '16', NULL, 'YES', 'BTREE', '', ''

Итак, это небольшой запрос ни при каких обстоятельствах.

Тот же самый запрос (с LEFTJOIN) с точно таким же дампом базы данных на моем локальном сервере разработки (меньше ресурсов) выполняется мгновенно.

Я уверен, что это не ресурс RDS "проблема, поскольку я удвоил экземпляр до t3.medium, и это не имело никакого значения.

Это наводит меня на мысль, что это ошибка индексации или некоторая конфигурация RDS c.

EXPLAIN:

ON RDS:

'1', 'SIMPLE', 'submissions', 'ALL', NULL, NULL, NULL, NULL, '1100', 'Using where'
'1', 'SIMPLE', 'explorer_points_earning', 'ALL', '_auto_for_trail', NULL, NULL, NULL, '17155', 'Range checked for each record (index map: 0x2)'

ON DEV:

'1', 'SIMPLE', 'submissions', NULL, 'ALL', NULL, NULL, NULL, NULL, '1064', '100.00', NULL
'1', 'SIMPLE', 'explorer_points_earning', NULL, 'ALL', '_auto_user,_auto_for_trail', NULL, NULL, NULL, '17082', '100.00', 'Using where; Using join buffer (hash join)'

Заметная разница в том, что RDS имеет только «auto_for_trail» как «возможный ключ», тогда как DEV имеет оба поля: _auto_user и _auto_for_trail. И RDS использует вложенный l oop и DEV с помощью ha sh join.

Без сомнения, я могу предоставить дополнительную информацию, чтобы помочь отладить это, но я не уверен, что, поэтому, пожалуйста, позвольте мне знаю, что еще может помочь.

Любая помощь, очень благодарна

Спасибо

- ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ -

SHOW CREATE TABLE cmsb_explorer_points_earning;

RDS

CREATE TABLE 
`cmsb_explorer_points_earning` (
    `num` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `createdDate` datetime NOT NULL, 
    `createdByUserNum` int(10) unsigned NOT NULL, 
    `updatedDate` datetime NOT NULL, 
    `updatedByUserNum` int(10) unsigned NOT NULL, 
    `user` mediumtext COLLATE utf8mb4_unicode_ci, 
    `points_earned` mediumtext COLLATE utf8mb4_unicode_ci, 
    `for_trail` mediumtext COLLATE utf8mb4_unicode_ci, 
    PRIMARY KEY (`num`), 
    KEY `_auto_for_trail` (`for_trail`(16)), KEY `_auto_user` (`user`(16))
) ENGINE=InnoDB AUTO_INCREMENT=17191 DEFAULT 
CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'

MySQL Версия: 5.6.10

DEV / LOCAL

CREATE TABLE         
`cmsb_explorer_points_earning` (
    `num` int unsigned NOT NULL AUTO_INCREMENT, 
    `createdDate` datetime NOT NULL, 
    `createdByUserNum` int unsigned NOT NULL, 
    `updatedDate` datetime NOT NULL, 
    `updatedByUserNum` int unsigned NOT NULL, 
    `user` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, 
    `points_earned` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, 
    `for_trail` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, 
    PRIMARY KEY (`num`), 
    KEY `_auto_user` (`user`(16)), KEY `_auto_for_trail` (`for_trail`(16))
) ENGINE=InnoDB AUTO_INCREMENT=17181 DEFAULT 
CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'

MySQL Версия: 8.0.20-0ubuntu0.20.04.1

1 Ответ

1 голос
/ 14 июля 2020

Добавьте это:

INDEX(user, for_trail)

На этом этапе INDEX(user) является избыточным и его следует удалить.

Если «пользователь» - это имя пользователя, вы делаете не необходимо MEDIUMTEXT (максимум 16 Мбайт). Также не требуется TEXT (максимум 64 Кбайт). Измените его на что-нибудь цивилизованное, например VARCHAR(100).

То же для другого MEDIUMTEXTs, если возможно. В этот момент предложенный мной индекс будет работать.

Другой обходной путь - использовать «префикс», как вы пытались:

KEY `_auto_for_trail` (`for_trail`(16)),
KEY `_auto_user` (`user`(16))

Но вы уже узнали, что это довольно бесполезно.

Кроме того, LIMIT без ORDER BY делает выбор из 15 строк непредсказуемым.

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