mysql выбирает порядок по первичному ключу. Представление

У меня есть таблица 'tbl' что-то вроде этого: ID bigint(20) - первичный ключ, автоинкремент field1 field2 field3

В этой таблице более 600 тыс. строк.

  1. Запрос: SELECT * from tbl ORDER by ID LIMIT 600000, 1 занимает 1,68 секунды
  2. Запрос: SELECT ID, field1 from tbl ORDER by ID LIMIT 600000, 1 занимает 1,69 секунды
  3. Запрос: ВЫБЕРИТЕ ID из tbl ORDER by ID LIMIT 600000, 1 занимает 0,16 секунды
  4. Запрос: SELECT * from tbl WHERE ID = xxx занимает 0,005 секунды

Эти запросы тестируются в phpmyadmin.

И в результате запрос 3 и запрос 4 вместе обязательно возвращают данные. Запрос 1 выполняет ту же работу, но намного медленнее...

Мне это не кажется правильным. Кто-нибудь может дать совет?

P.S. Прошу прощения за форматирование. Я новичок на этом сайте.

Новый тест:

Q5: СОЗДАЙТЕ ВРЕМЕННУЮ ТАБЛИЦУ tmptable AS (ВЫБЕРИТЕ ID FROM tbl WHERE ID LIMIT 600030, 30); SELECT * FROM tbl WHERE ID IN (SELECT ID FROM tmptable); занимает 0,38 сек.

Я до сих пор не понимаю, как это возможно. Я воссоздал все индексы. Что еще я могу сделать с этой таблицей? Удалить и заполнить вручную? :)


person IGonza    schedule 27.06.2013    source источник


Ответы (1)


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

Запрос 2 просматривает индекс первичного ключа таблицы, находит правильные 600 000 идентификаторов и их соответствующие местоположения в таблице, затем переходит к таблице и извлекает подмножество полей, запрашиваемых из этих 600 000 строк.

Запрос 3 просматривает индекс первичного ключа таблицы, находит правильные идентификаторы 600k и возвращает их. Совершенно не обязательно смотреть на стол.

Запрос 4 просматривает индекс первичного ключа таблицы, находит запрошенную единственную запись, обращается к таблице, считывает эту единственную запись и возвращает ее.

По времени давайте построим в обратном порядке:

(Q4) Индекс таблицы позволяет искать ключ (id) за время O(log n), то есть каждый раз, когда размер таблицы удваивается, требуется всего один дополнительный шаг, чтобы найти ключ в индексе*. Если у вас есть 1 миллион строк, то для его поиска потребуется всего около 20 шагов. Миллиард строк? 30 шагов. Запись индекса включает данные о том, где в таблице нужно найти данные для этой строки, поэтому MySQL переходит к этому месту в таблице и читает строку. Время, указанное для этого, почти полностью накладное.

(Q3) Как я уже упоминал, индекс таблицы работает очень быстро; этот запрос находит первую запись и просто проходит по дереву, пока не наберет запрошенное количество строк. Я уверен, что смогу рассчитать точное количество шагов, которое потребуется, но как максимум мы скажем, что 20 шагов x 600 тысяч строк = 12 миллионов шагов; поскольку он пересекает дерево, это, вероятно, будет больше похоже на 1 миллион шагов, но точное число в значительной степени не имеет значения. Самое важное, что нужно понять, это то, что после того, как MySQL пройдется по индексу, чтобы получить нужные ему идентификаторы, у него будет все, что вы просили. Нет необходимости идти смотреть на стол. Время, указанное для этого, по сути, является временем, которое требуется MySQL для обхода индекса.

(Q2) Это начинается с того же обхода дерева, который обсуждался для запроса 3, но при извлечении необходимых ему идентификаторов MySQL также извлекает их местоположение в файлах таблиц. Затем он должен перейти к файлу таблицы (возможно, уже кэшированному/mmapped в памяти) и для каждой извлеченной записи искать нужное место в таблице и получать запрошенные поля из этих строк. Время, сообщаемое для этого запроса, — это время, необходимое для обхода индекса (как в вопросе 3), плюс время для посещения каждой строки, указанной в индексе.

(Q1) Это идентично Q2, когда указаны все поля. Поскольку время, по сути, идентично Q2, мы можем видеть, что на самом деле не требуется значительно больше времени, чтобы извлечь больше полей из базы данных, каждый раз, когда они затмеваются сканированием индекса и поиском строк.

*: В большинстве баз данных используется индексирующая структура данных (B-деревья для MySQL), которая имеет база журнала намного выше 2, а это означает, что вместо дополнительного шага каждый раз, когда таблица удваивается, это больше похоже на дополнительный шаг каждый раз, когда размер таблицы увеличивается в сотни или тысячи раз. Это означает, что вместо 20-30 шагов, которые я указал в примере, это скорее 2-5.

person Kevin    schedule 27.06.2013
comment
Все еще читаю, но краткое примечание: LIMIT 600000, 1 - это означает, что он выбирает только 1 строку, начиная с строки 600000. - person IGonza; 27.06.2013
comment
Пропустил , 1. В этом случае разница между 1/2 и 3 может заключаться в кэшировании. 4 по-прежнему является прямым поиском, тогда как другие по-прежнему требуют обхода индекса. - person Kevin; 27.06.2013
comment
Я установил размер кэш-памяти равным 0 в конфигурации mysql, поэтому результаты не кэшируются. - person IGonza; 27.06.2013
comment
Я не понимаю, почему есть существенная разница в скорости Q2 и Q3. И почему Q3+Q4 работает быстрее, чем Q2? - person IGonza; 27.06.2013
comment
Комбинируя Q3+Q4, я могу получить тот же результат, что и Q2. - person IGonza; 27.06.2013
comment
Теперь я понимаю, что вы имеете в виду. Был ли идентификатор, который вы использовали, в 4 верхнем или нижнем (т.е. в начале файла или в конце)? Я почти уверен, что MySQL ищет, но если нет, это может быть местоположение в файле. В противном случае на это могло повлиять кэширование диска (на уровне ОС). - person Kevin; 27.06.2013
comment
Также возможно, что это просто сбой оптимизации mysql, известно, что в некоторых ситуациях он неоптимален. - person Kevin; 27.06.2013
comment
в Q4 я использовал один из возвратов id Q3. И Q3 возвращает 600001, 600002... Также это новая установка сервера mysql. Просто установил его с конфигурацией по умолчанию. И вообще... 1,6 секунды мне кажется слишком медленными. Я ошибаюсь? - person IGonza; 27.06.2013
comment
Я только что заполнил тестовую БД примерно 1 млн строк, и это заняло 0,13, 0,12, 0,09 и 0,00 секунды (для Q 1-4 соответственно). 1,6 секунды определенно кажутся подозрительно длинными, хотя мои данные также показывают разрыв между 1/2 и 3+4. - person Kevin; 27.06.2013
comment
Спасибо, Кевин, за ваши ответы. Я попытаюсь создать новую таблицу и заполнить ее случайными данными... и, возможно, воссоздать существующую таблицу. Я отпишусь, если получу интересные результаты - person IGonza; 27.06.2013
comment
Общий вывод: используйте EXPLAIN в своих запросах, чтобы узнать, что они делают. Q3 быстрее, чем Q2, потому что он не загружает таблицу в память, как указывает Кевин в своем ответе. Q4 самый быстрый, потому что гораздо быстрее перейти непосредственно к индексированному значению, чем пройти по дереву до N-го значения. Тайны кэширования нет. Просто план запроса отличается для каждого запроса (кроме Q1 и Q2). - person Andrew; 21.09.2018