Медленное восстановление MySQL строки с наибольшим значением в индексированном столбце - PullRequest
0 голосов
/ 16 сентября 2009

У меня есть таблица SQL readings что-то вроде:

id int
client_id int
device_id int
unique index(client_id, device_id)

Я не понимаю, почему следующий запрос такой медленный:

SELECT client_id FROM `readings` WHERE device_id = 10 ORDER BY client_id DESC LIMIT 1

Я понимаю, что с индексом mysql хранит упорядоченный список (одно свойство btree) каждой строки в таблице, отсортированный сначала по client_id, а затем по device_id. Когда я выполняю объяснение по этому запросу, он говорит, что будет использовать индекс, но ему нужно будет просмотреть каждую строку. Это имеет смысл, поскольку в худшем случае может быть только одна строка с device_id = 10, и это также может быть строка с наименьшим client_id и, следовательно, в конце его поиска. Однако на практике это не так. В моей таблице ~ 10 миллионов строк, и строки с device_id = 10 распределены по этой таблице довольно равномерно. Почему тогда MySQL не запускается в конце индекса и не сканирует, пока не найдет первую строку с device_id = 10, не остановится и не вернет это значение? Кажется невозможным, что это происходит, поскольку выполнение запроса занимает ~ 30 секунд.

Неужели мой уникальный ключ каким-то образом реализован в виде хэша и поэтому недоступен в виде списка? PHPMyAdmin говорит мне, что он реализован в виде b-дерева, что заставляет меня думать, что он должен быть в состоянии выполнить сканирование, как я упоминал выше, и завершить работу с первым экземпляром.

Где моя ошибка и как я могу выполнить этот запрос быстрее?

Спасибо

Ответы [ 3 ]

3 голосов
/ 16 сентября 2009

Попробуйте изменить порядок столбцов в индексе:

unique index(device_id, client_id)

Поскольку вы фильтруете по device_id, вы бы хотели, чтобы это был первый столбец в индексе.

0 голосов
/ 16 сентября 2009

У вас есть составной индекс (client_id, device_id), он будет (более или менее) объединен для целей индексации, и индекс будет учитываться только при использовании первый из столбца (ов). Ваш запрос использует 'device_id', который является последним из них, вы можете предоставить отдельный индекс для этого столбца или поменять местами столбцы в индексе.

Кроме того, проверьте вывод EXPLAIN для ваших запросов.

0 голосов
/ 16 сентября 2009

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

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

SELECT MAX(client_id) from readings where device_id = 10

В противном случае вы можете изменить индекс сначала на device_id, а затем client_id. Или вы можете добавить еще один индекс просто device_id.

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