MySQL не использует все ключевые части составного индекса - PullRequest
0 голосов
/ 14 мая 2018

У меня есть таблица InnoDB, содержащая ~ 1,7 млн ​​строк в MySQL 5.7.19 .Я хочу оптимизировать следующий запрос:

select * from `table` where `col1` = 'x' and `col2` = 123 and `col3` = 'z'

, где столбцы определены как (все используют кодировку utf8mb4):

col1 varchar(255) null
col2 varchar(255) not null
col3 varchar(255) not null

и индекс для всех столбцов:

key (
  col1, -- Cardinality: 40
  col2, -- Cardinality: 472810
  col3  -- Cardinality: 403767
)

Я ожидаю, что запрос будет выполняться быстро, потому что MySQL должен быть в состоянии полностью использовать индекс.Теперь производительность не так хороша, и она начинает иметь смысл, когда я запускаю запрос с explain format=json:

"used_key_parts": [
   "col1"
],
"key_length": "1022"

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

Может ли кто-нибудь объяснить мне, что здесь происходит, и дать совет, как это исправить?

Iв настоящее время это решается путем объединения столбцов в один столбец, путем введения и индексации сохраненного сгенерированного столбца, который объединяет col1 и col2.Однако я не могу использовать это для запросов, которые хотят использовать оператор IN() в этих столбцах.

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

Jarno

Ответы [ 3 ]

0 голосов
/ 14 мая 2018

Спасибо всем за ваш ответ. Поработав с порядком столбцов в индексе (связанном с количеством элементов), я заметил, что приложение сравнивалось с целочисленным значением в col2 (который является столбцом varchar). Преобразование значения в строку решило проблему производительности.

0 голосов
/ 20 мая 2018
`col2` = 123

- твоя смерть.При сравнении VARCHAR с целочисленной константой varchar преобразуется в числовой.Это требует преобразования всех соответствующих строк на лету.

В конце концов, col2 может содержать "0123" или "123.0" или "1.23e2".Что касается строк, то они совершенно разные;индексы на varchars сортируются в соответствии с string атрибутами (COLLATION).

Вероятное решение состоит в том, чтобы изменить кавычки:

`col2` = "123"

ПорядокANDs в WHERE не имеет значения.

Порядок столбцов в INDEX имеет значение.Было бы лучше иметь INDEX с col1 и col3 в любом порядке.

Количество элементов имеет значение при сравнении INDEX(col1) с INDEX(col3).

Количество элементов имеет значение не имеет значение для фактически используемых частей индекса, как при сравнении INDEX(col1, col3) с INDEX(col3, col1).

В отличие от WHERE int_col = "123" будет преобразовывать "123" к 123 иметь возможность использовать индекс.

0 голосов
/ 14 мая 2018

попробуйте построить ваш композит, используя столбцы с высокой кардинальностью

Например:

col2,col3,col1 

и используйте тот факт, что вы используете оператор AND, где не требуется () для выполнения условия

  select * from `table` where `col1` = 'x' and `col2` = 'y' and `col3` = 'z' 

и, наконец, вы можете наложить индекс с помощью FORCE

...