Индексированный столбец и неиндексированный столбец исследования - PullRequest
0 голосов
/ 11 октября 2018

Я сгенерировал отдельные таблицы MySQL Innodb с 2000, 5000, 10000, 50000, 10000, 20000, 50000, 100 000, 200 000 элементов (с помощью цикла php и запроса вставки).Каждая таблица имеет два столбца: id (автоинкремент первичного ключа INT), номер (INT UNIQUE KEY).Затем я сделал то же самое, но на этот раз я создал аналогичные таблицы, в которых столбец number не имеет таблицы INDEX .I, сгенерированной таким образом: значение столбца number равно значению индекса + 2: первый элемент == 3, 1000-й элемент равен 1002 и так далее.Я хотел протестировать такой запрос, потому что он будет использоваться в моем приложении:

SELECT count(number) FROM number_two_hundred_I WHERE number=200002;

После генерации данных для этих таблиц я хотел проверить время для запросов в худшем случае.Я использовал SHOW PROFILES для этого.Я сделал предположение, что запрос в худшем случае будет соответствовать элементу со значением от столбца число до 1002, 2002 и т. Д., Так что здесь приведены все запросы, которые я проверял, и время (оценивается SHOWПРОФИЛИ):

SELECT count(number) FROM number_two_thousand_I WHERE number=2002;
// for tables with indexed column number I used **suffix _I** in the end 
// of name of the table. Here is the time for it 0.00099250
SELECT count(number) FROM number_two_thousand WHERE number=2002;
// column number is not indexed when there is no **suffix _I** 
// time for this one is 0.00226275
SELECT count(number) FROM number_five_thousand_I WHERE number=5002;
// 0.00095600
SELECT count(number) FROM number_five_thousand WHERE number=5002;
// 0.00404125

Итак, вот результаты:

  1. 2000 эл. - проиндексировано 0.00099250, не проиндексировано - 0.00226275

  2. 5000 el - проиндексирован 0.00095600 не проиндексирован - 0.00404125

  3. 10000 el - проиндексирован 0.00156900 не проиндексирован - 0.00761750

  4. 20000 el - проиндексирован 0.00155850 не проиндексирован - 0.01452820
  5. 50000 el - проиндексирован 0.00051100 не проиндексирован - 0.04127450
  6. 100000 el проиндексирован 0.00121750 не проиндексирован - 0.07120075
  7. 200000 el проиндексирован 0.00095025 не проиндексирован - 0.11406950

Вот инфографика за это.Он показывает, как количество элементов зависит от наихудшего времени запроса для индексированного / неиндексированного столбца.Индексируется красным цветом. Когда я тестировал скорость, я набирал один и тот же запрос в консоли mysql 2 раза , потому что я понял, что когда вы делаете запрос в первый раз, иногда запрос по неиндексированному столбцу может быть даже немного быстрее, чемдля индексированного.Вопрос в том, почему этот тип запроса для 200000 элементов занимает иногда меньше времени, чем тот же запрос для 100000 элементов, когда индексируется номер столбца.Вы можете видеть, что есть другие непредсказуемые для меня результаты.Я спрашиваю об этом, потому что, когда номер столбца не проиндексирован, результаты вполне предсказуемы: время 200000 эл всегда больше 100000. Пожалуйста, скажите мне, что я делаю неправильно, когда пытаюсь исследовать индексированный столбец UNIQUE.

Ответы [ 2 ]

0 голосов
/ 13 октября 2018

Это не «наихудший» случай.

  • Сделайте ключ UNIQUE случайным, вместо того, чтобы находиться в шаге блокировки с PK.Примером этого является UUID().
  • Генерирование достаточного количества строк, чтобы таблица и индекс (ы) не могли поместиться в buffer_pool.

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

UNIQUE ключи оказывают следующее влияние на INSERTs: ограничение уникальности проверяется перед возвратом клиенту.Для неуникального индекса работа по вставке в BTree индекса может (и является) отложена.(см. «Изменить буфер»). Без индекса во втором столбце работы еще меньше.

WHERE number=2002 -

  • С UNIQUE(number) - Детализациявниз по BTree. Очень быстрый, очень эффективный.
  • с INDEX(number) - развернуть BTree. Очень быстрый, очень эффективный. Однако он немного медленнее, поскольку не может предположить, что существует только один такой рядТо есть после нахождения правильного места в BTree он будет сканировать вперед (очень эффективно), пока не найдет значение, отличное от 2002.
  • Без индекса number - Сканирование всей таблицы.Таким образом, стоимость зависит от размера таблицы, а не от значения number. Она не имеет ни малейшего понятия, существует ли где-нибудь в таблице 2002 год или сколько раз. Если вы построите график времени, которое вы получили, вы увидите, что он довольно линейный.

Я предлагаю вам использовать log-log 'paper' для вашего графика. В любом случае, обратите внимание, насколько линейным является неиндексированный регистр. И индексированный регистр по существу постоянен. Нахождение числа = 200002 так же, какдешево как найти число = 2002. Это относится к UNIQUE и INDEX.(На самом деле в линии наблюдается очень небольшое увеличение, потому что BTree - это действительно O (log n), а не O (1). Для строк 2K в BTree, вероятно, есть 2 уровня; для 200K - 3 уровня.)

Кеш запросов может сбить вас с толку в моменты времени (если он включен).При выборе времени сделайте SELECT SQL_NO_CACHE ..., чтобы избежать контроля качества.Если контроль качества включен и применяется, то выполнение второго и последующих запросов идентичных займет очень близко к 0,000 секунд.

Те временные интервалы, которые варьировались между 0,5мс и 1,2 мс - мела до фазы луны.Серьезно, нельзя доверять любому времени менее 10 мс.Это из-за всех других вещей, которые могут происходить на компьютере одновременно.Вы можете несколько умерить его, усреднив несколько запусков - обязательно избегая (1) кеша запросов и (2) ввода / вывода.

Что касается ввода / вывода ... Это возвращается к моему ранеепрокомментируйте, что может произойти, если таблица (и / или индекс) больше, чем может быть кэширована в ОЗУ.

  • Если размер меньше ОЗУ, то при первом запуске может быть получено содержимое с диска.Второй и последующие запуски, вероятно, будут более быстрыми и последовательными.
  • Поскольку объем больше, чем ОЗУ, все запуски могут потребоваться для попадания на диск.Следовательно, all может быть медленным и, возможно, более ненадежным, чем найденные вами варианты.

Ваши теги технически неверны.Большинство индексов MySQL - это BTrees (фактически B + Trees), а не Binary Trees.(Конечно, есть много общего, и многие принципы разделены.)

Возвращаясь к цели вашего исследования.

  • Предположим, что есть "фоновый шум", который мешаетс вашими цифрами.
  • Сделайте ваши тесты нетривиальными (например, неиндексированный регистр), чтобы он подавлял шум, или
  • Повторите время, чтобы скрыть проблему.И обязательно не обращайте внимания на первый запуск.

Стоимость main при выполнении любого SELECT равна количеству строк, к которым он прикасается.

  • Сваш UNIQUE индекс, он касается 1 строки.Так что ожидайте быстро и O (1) (плюс шум).
  • Без индекса это касается N строк для таблицы N-строк.Так что ожидайте O (N).
0 голосов
/ 11 октября 2018

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

...