#mysql
#mysql
Вопрос:
У меня есть следующая таблица с включенным индексом id
и внешним ключом activityID
:
comment (id, activityID, text)
и следующий запрос:
SELECT <cols> FROM `comment` WHERE `comment`.`activityID` = 1257 ORDER BY `id` DESC LIMIT 20;
По сути, я хочу получить только первые 20 комментариев для этого действия, которое содержит 1165, однако это результат описания:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE comment ref activityID activityID 4 const 1165 NULL
По сути, он просматривает все комментарии для этого действия, прежде чем принять решение ограничить его.
Мы тестировали этот запрос при высокой нагрузке, когда действие содержит 200 000 комментариев и запрос занимает более 5 секунд, тогда как при той же загрузке действие с 30 комментариями занимает пару мс.
PS: Если я удалю WHERE
предложение, в EXPLAIN говорится, что он будет искать только одну строку (не знаю, так ли это на самом деле):
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE comment index NULL PRIMARY 4 NULL 1 NULL
Возможно ли каким-либо образом оптимизировать такого рода запросы?
Спасибо.
Комментарии:
1. Что произойдет, если вы добавите
ORDER BY
предложение? ОГРАНИЧЕНИЕ без ORDER BY обычно пахнет кодом, поскольку вы не знаете, какие 20 вы получите.2. На самом деле запрос, который мы используем, содержит
ORDER BY id DESC
предложение. Я обновлю.3. Вероятно, это не имеет большого значения, на самом деле было бы конкретизировано с помощью выбора;
SELECT `text` FROM
а не*
?4. Фактический код выбирает определенные столбцы, я просто удалил это, чтобы упростить чтение, и это не имело бы никакого значения.
Ответ №1:
Упорядочение вызывает медлительность.
Запрос использует activityID
индекс, чтобы найти все строки с этим идентификатором. Затем он должен прочитать все 200 000 комментариев и отсортировать их по id
, чтобы найти последние 20.
Добавьте составной индекс, чтобы он мог использовать индекс для упорядочивания:
ALTER TABLE comment ADD INDEX (activityID, id);
Обратите внимание, что вам больше не понадобится индекс на activityID
сам по себе, поскольку это префикс этого нового индекса.
Комментарии:
1. Это не имело никакого значения. Пробовал без какого-либо упорядочения, пробовал упорядочивать по идентификатору с тем индексом, который вы предложили, и
EXPLAIN
возвращает точно то же самое.2. Даже после того, как вы удалили старый индекс?
3. Это внешний ключ
4. Все в порядке. Поскольку это префикс этого нового ключа, он все равно будет использоваться в качестве внешнего ключа.
5. Я хочу сказать, что
ORDER BY
это не имеет никакого значения, я даже пробовал использоватьFORCE INDEX (
activityID_id)
, и это то же самое.
Ответ №2:
Используйте смещение
SELECT <cols> FROM `comment` WHERE `comment`.`activityID` = 1257 ORDER BY `id` DESC LIMIT 0,20;
В предложении limit добавьте 0
в качестве смещения, чтобы получить только первые 20 комментариев
Комментарии:
1. Но значение по умолчанию для смещения равно нулю, если смещение не указано, так что, похоже, это на самом деле ничего не меняет?
2. О, извините за мою ошибку
Ответ №3:
Просто добавьте два отдельных индекса на activityID
и id
. Это тоже должно вам помочь ORDER BY
. В оптимизации нет жестких правил, но вам нужно попробовать различные методы.
Сделайте это таким образом:
ALTER TABLE comment ADD INDEX (id);
ALTER TABLE comment ADD INDEX (activityID);
Я думаю, это поможет.
Комментарии:
1.
id
всегда указывайте индекс по умолчанию.activityID
является внешним ключом.2. Я не знаю, почему вы отклонили мой ответ, вы нигде не написали, что ваш
id
является первичным ключом в вопросе. Вот почему я написал, чтобы убедиться в этом. В любом случае, еслиid
это первичный ключ, вам все равно нужно создать индекс наactivityID
. Поскольку внешние ключи автоматически не индексируются в движке MyISAM, а только в InnoDB. Кроме того, это общее эмпирическое правило, согласно которому SQL-запрос будет проходить через все записи, которые являются частью выполненного условия индекса. В случае, если вы хотите еще больше снизить свои результаты, вам демонстративно нужно использовать несколько составных комбинаций клавиш, чтобы добиться меньшего количества строк.