Вы заметили, что используются только четыре столбца индекса:
"used_key_parts": [
"country",
"city",
"gender",
"birth_date"
],
Несмотря на условия в вашем предложении WHERE, ссылающиеся на все пять столбцов:
WHERE
pro.country = 'INDONESIA'
AND pro.city IN ( 'MAKASSAR' )
AND pro.gender = 0
AND ( pro.birth_date BETWEEN ( NOW()- INTERVAL 35 YEAR ) AND ( NOW()- INTERVAL 25 YEAR ) )
AND pro.orderid > 0
Однако, в этих условиях что-то другое. Все условия country
, city
, gender
являются условиями равенства . Как только поиск находит подмножество индекса с этими значениями, тогда подмножество упорядочивается по birth_date
следующим, а если есть строки, привязанные к birth_date
, они дополнительно упорядочиваются по orderid
.
Также как если вы читаете телефонную книгу и находите всех людей, чья фамилия «Смит», они отсортированы по имени. Если есть несколько человек с одинаковым именем, они упорядочиваются в телефонной книге по их соответствующему номеру телефона.
Smith, Sarah 408-555-1234
Smith, Sarah 408-555-5678
Но что, если вы выполните поиск всех людей с фамилией Смит и различные имена, начинающиеся с "S"?
Smith, Sam 408-555-3298
Smith, Sarah 408-555-1234
Smith, Sarah 408-555-5678
Smith, Stan 408-555-4224
Они не отсортированы по номерам телефонов. Они сортируются по фамилии, затем по имени, а затем по номеру телефона, только если они привязаны к предыдущим столбцам.
Если вы хотите отсортировать их по номеру телефона, вы можете создать индекс со столбцами в другой порядок, например фамилия, номер телефона, имя.
Smith 408-555-1234 Sarah
Smith 408-555-2020 David
Smith 408-555-3298 Sam
Smith 408-555-4100 Charlie
Smith 408-555-4224 Stan
Smith 408-555-5555 Annette
Smith 408-555-5678 Sarah
Теперь они расположены в порядке номеров телефонов, но среди них есть и другие имена, которые не соответствуют вашему условию для имен, начинающихся с " S ". Они даже не отсортированы по имени, потому что третий столбец для имени будет отсортирован только тогда, когда первые два столбца будут связаны.
Это указывает на общую проблему с индексами: вы можете изменить порядок столбцы только для столбцов, участвующих в сравнениях равенство . Если вы хотите отсортировать результаты, вы можете использовать индекс только в том случае, если вы сортируете по столбцу в индексе и все предыдущие столбцы индекса используются только для сравнения на равенство.
После ссылки на один столбец в диапазон сравнение, любые последующие столбцы в индексе игнорируются как для поиска, так и для сортировки.
Другими словами: индекс может иметь любое количество столбцов для условий равенства, а следующий столбец index может использоваться либо для условия диапазона, либо для сортировки результатов. Но для любой из этих операций используется не более одного столбца.
Вы не можете оптимизировать все.
Повторите свой комментарий: Если у вас есть индекс по столбцам, исключая birth_date
:
alter table profiles3m add key bk1 (country, city, gender, orderid);
Тогда EXPLAIN показывает, что сортировка файлов отсутствует:
EXPLAIN SELECT
pro.uid
FROM
`profiles3m` AS pro
WHERE
pro.country = 'INDONESIA'
AND pro.city IN ( 'MAKASSAR' )
AND pro.gender = 0
AND ( pro.birth_date BETWEEN ( NOW()- INTERVAL 35 YEAR ) AND ( NOW()- INTERVAL 25 YEAR ) )
AND pro.orderid > 0
ORDER BY
pro.orderid
LIMIT 30\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: pro
partitions: NULL
type: range
possible_keys: bk1
key: bk1
key_len: 489
ref: NULL
rows: 1
filtered: 100.00
Extra: Using index condition; Using where
(rows
выглядит низким, потому что я тестирую это с пустой таблицей.)
Предостережение заключается в том, что при этом используется индекс для соответствия всем строкам, сопоставленным country
, city
, gender
и orderid
. Затем MySQL будет оценивать оставшееся условие на birth_date
сложным способом: строка за строкой.
Но после этого оптимизатор знает, что он уже получил строки в порядке индекса, поэтому он знает, что естественно будет в порядке orderid
, так что он может пропустить сортировку файлов.
Это может быть или не быть net победой. Это зависит от того, сколько строк сопоставлено, но должно быть выброшено условием birth_date
. И насколько дорого стоит оценивать это условие для каждой строки. И как это соотносится с экономией, которую вы получили бы, используя индекс для фильтрации по birth_date
.