2016-08-13 1 views
-4

У меня есть очень простую таблицу с тремя столбцами:MySQL - Низкая производительность в выберите из простой таблицы

- A BigINT, 
- Another BigINT, 
- A string. 

Первые два столбца определяется как INDEX и нет никаких повторов. Более того, оба столбца имеют значения в растущем порядке.

В таблице содержится почти 400 тыс. Записей.

нужно выбрать строку, когда значение находится в пределах тех из колонны 1 и два, в порядке слов:

SELECT MyString 
    FROM MyTable 
WHERE Col_1  <= Test_Value 
    AND Test_Value <= Col_2  ; 

В результате может быть либо не найден или одно значение.

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

Я проверил тип индекса, и он равен BTREE для обоих столбцов (1 и 2).

Любая идея, как улучшить производительность?

Заранее спасибо.

EDIT: Explain, гласит:

Выберите тип: Простой, Тип: Range, Возможные ключи: ОСНОВНОЙ Ключ: первичный, Длина ключа: 8, Ряды: 441, фильтрованной: 33,33 , Дополнительно: Использование где.

+3

имеют составной индекс? – YOU

+0

При поиске рекомендаций по производительности необходимо показать свою точную структуру таблицы и индексы. Также полезно использовать команду EXPLAIN, чтобы заставить планировщик запросов описать, что он делает. Пожалуйста, отредактируйте свой вопрос, чтобы включить эти предметы. –

+0

Нет составного индекса @YOU. – FDavidov

ответ

2

Если я правильно понял вашу обфускацию, у вас есть значение start и end, такое как дата-время или IP-адрес в паре столбцов? И вы хотите узнать, соответствует ли ваш данный datetime/ip заданному диапазону?

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

Итак, оптимизатор, в лучшем случае, использует индекс, начинающийся с start или end и сканируя половину стола. Неэффективно.

Являются ли диапазоны неперекрывающимися? IP Addresses

Что вы можете сказать о результате? Возможно, такой клод будет работать: SELECT ... WHERE Col_1 <= Test_Value ORDER BY Col_1 DESC LIMIT 1.

+0

Спасибо @RickJames за ваш ответ. что добавление «ORDER» и «LIMIT» делает существенную разницу. Однако потребуются дополнительные тесты. Будет обновляться, когда будут достигнуты убедительные результаты. В соответствии с IP-адресом нет, но очень похоже на это. – FDavidov

1

Ваш запрос, переписан с более короткими идентификаторами, это

SELECT s FROM t WHERE t.low <= v AND v <= t.high 

Чтобы удовлетворить этот запрос с использованием индексов будет идти, как это: Во-первых, мы должны искать таблицу или индекс для всех строк, соответствующих первому из этих критериев

t.low <= v 

Мы можем думать об этом как о половинной проверке индекса BTREE. Он начинается в начале и останавливается, когда он доходит до v.

Требуется другое полусканирование в другой индекс для удовлетворения v <= t.high. Затем требуется слияние двух наборов результатов для определения строк, соответствующих двум критериям. Проблема в том, что два набора результатов для объединения большие, и они почти полностью не перекрываются.

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

Возможно, вы можете или не можете ускорить этот точный запрос с помощью составного индекса на (low, high, s) - с вашими первоначальными именами столбцов (Col_1, Col_2, MyString). Это называется covering index и позволяет MySQL полностью удовлетворять запросу из индекса. Иногда это помогает. (Было бы легче догадаться, поможет ли это, если будет доступно точное определение вашей таблицы, эффективность покрытия индексов зависит от таких вещей, как другие индексы, первичные ключи, размер столбца и т. Д. Но вы выбрали минимальное раскрытие информации для этой информации.)

Что здесь действительно поможет? Переосмысление вашего алгоритма может сделать вам много хорошего. Кажется, вы пытаетесь получить строки, где контрольная точка v находится в диапазоне [t.low, t.high]. Использует ли ваша заявка априорный лимит на ширину диапазона? То есть существует ли известное максимальное значение t.high - t.low? Если это так, давайте назовем это значение maxrange. Затем вы можете переписать запрос так:

SELECT s 
    FROM t 
    WHERE t.low BETWEEN v-maxrange AND v 
    AND t.low <= v AND v <= t.high 

Когда maxrange доступен, мы можем добавить пункт col BETWEEN const1 AND const2. Это приводит к эффективному сканированию диапазона по индексу на low. В этом случае упомянутый выше индекс покрытия, безусловно, ускорит этот запрос.

Прочтите это. http://use-the-index-luke.com/

+0

Большое спасибо @OllieJones или Подробное объяснение (и время, потраченное на его формулировку!). Некоторые комментарии: 1) Я не скрывал информацию вообще. Таблица ** точно ** как описано (два столбца BigInt и строка с индексом в первых двух столбцах); 2) К сожалению, не существует заранее заданного диапазона для разности между max и min (т. Е. 'T.high-t.low'); 3) Контрольное значение 'v' - это случайное число. – FDavidov

0

Ну ... Я нашел подходящее решение для меня (не уверен, что вашим парням это понравится, но, как сказано, это работает для меня).

я просто распределял мои 400K записей в нескольких таблицах и создал простую таблицу, которая служит в качестве селектора:

В таблице селектора имеет минимальное значение первого столбца для каждого раздела вместе с простым индексом (т.е. 1, 2,, ...).

Я тогда пользователь следующий, чтобы получить индекс таблицы, которая должна содержать искали диапазон, как:

SELECT Table_Index 
    FROM tbl_selector 
WHERE start_range <= Test_Val 
ORDER BY start_range DESC LIMIT 1 ; 

Это даст мне индекс таблицы Я хочу, чтобы выбрать из.

Затем у меня есть СЛУЧАЙ по восстановленному индексу, чтобы выбрать правильную таблицу разделов для выполнения фактического поиска.

(Я думаю, что более элегантным было бы использование Dynamic SQL, но позаботимся об этом позже, а пока просто нужно проверить подход).

В результате я получаю ответ значительно ниже секунды (~ 0,08) и он равномерен независимо от числа, используемого для теста.Это, кстати, не имело места с предыдущим подходом: там, если число было «близко» к началу таблицы, результат был произведен довольно быстро; если, с другой стороны, запись была ближе к концу таблицы, для завершения потребуется несколько секунд).

[Кстати, я полагаю, вы понимаете, что я имею в виду начала и конец стола]

Опять же, я уверен, что люди, возможно, не нравится, но это делает работу для меня ,

Благодарю вас за усилия по оказанию помощи !!