Индексируйте запрос "ГДЕ А IN (1,2,3) И b = 4" - PullRequest
0 голосов
/ 22 марта 2012

Я пытаюсь применить индекс, который ускорит один из самых медленных запросов в моем приложении:

SELECT * FROM orders WHERE product_id IN (1, 2, 3, 4) AND user_id = 5678;

У меня есть индекс product_id, user_id и пара (product_id, user_id). Однако сервер не использует ни один из этих индексов:

+----+-------------+------- +------+-------------------------------------------------------------------------------------------+------+---------+------+------+-------------+
| id | select_type | table  | type | possible_keys                                                                             | key  | key_len | ref  | rows | Extra       |
+----+-------------+--------+------+-------------------------------------------------------------------------------------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | orders | ALL  | index_orders_on_product_id,index_orders_on_user_id,index_orders_on_product_id_and_user_id | NULL | NULL    | NULL |    6 | Using where |
+----+-------------+--------+------+-------------------------------------------------------------------------------------------+------+---------+------+------+-------------+

(В разработке только 6 строк, так что в любом случае, но в производстве около 400 тыс. Строк, поэтому выполнение занимает около 0,25 с, и этот запрос выполняется довольно часто.)

Как мне избежать простого WHERE здесь? Я полагаю, что мог бы отправить запрос для каждого product_id, который, вероятно, был бы быстрее, чем эта версия, но число продуктов могло бы быть очень большим, поэтому, если это выполнимо в одном запросе, это было бы значительно предпочтительнее. Этот запрос генерируется Rails, поэтому я немного ограничен в том, насколько я могу реструктурировать сам запрос. Спасибо!

Ответы [ 2 ]

5 голосов
/ 22 марта 2012

Для оптимальной производительности этого конкретного запроса в вашей рабочей таблице (с 400k строками) вам нужен составной индекс для {user_id, product_id}, в для этого порядка .

В идеале это будет индекс only , и вы будете использовать InnoDB, чтобы таблица была кластеризованной . Каждый дополнительный индекс влечет за собой штраф за изменение данных, и вдобавок к этому вторичные индексы в кластеризованных таблицах даже дороже , чем вторичные индексы в таблицах на основе кучи.

Чтобы понять, почему user_id (а не product_id) должен находиться на переднем крае индекса, взгляните на Анатомия индекса . По сути, поскольку WHERE ищет только один user_id, то при его первом кластеризации соответствующие значения product_id располагаются ближе в индексе.

({product_id, user_id} также будет работать, но будет "рассеивать" "целевые" узлы индекса менее выгодно.)

4 голосов
/ 22 марта 2012

Когда в базе данных так мало строк, она не использует индексы, потому что дешевле выполнить полное сканирование. Попробуйте проверить данные в вашей среде prod и посмотрите, использует ли она один из ваших индексов.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...