Почему MySQL не использует мой индекс? Оптимизация запроса выбора MySQL - PullRequest
2 голосов
/ 02 сентября 2011

Я пытаюсь оптимизировать запрос выбора MySQL:

SELECT * FROM `sales` 
WHERE ((sales.private = false AND (sales.buyer_id IS NULL OR NOT sales.buyer_id=142)
  AND (sales.merchand_id IS NULL OR NOT sales.merchand_id=142)
  AND (sales.private_item = false) )
  AND ((sales.buyer_id=32 OR sales.merchand_id=32)
  AND (sales.admin=0 AND NOT sales.type IN ('book'))))
ORDER BY sales.created_at DESC, sales.id DESC LIMIT 0, 10;

Схема таблицы:

mysql> SHOW columns from sales;
+------------------------+--------------+------+-----+---------+----------------+
| Field                  | Type         | Null | Key | Default | Extra          |
+------------------------+--------------+------+-----+---------+----------------+
| id                     | int(11)      | NO   | PRI | NULL    | auto_increment |
| type                   | varchar(255) | YES  | MUL | NULL    |                |
| buyer_id               | int(11)      | YES  | MUL | NULL    |                |
| merchand_id            | int(11)      | YES  | MUL | NULL    |                |
| private                | tinyint(1)   | YES  |     | 0       |                |
| admin                  | tinyint(1)   | YES  |     | 0       |                |
| created_at             | datetime     | YES  |     | NULL    |                |
| updated_at             | datetime     | YES  |     | NULL    |                |
| country_id             | int(11)      | YES  | MUL | 0       |                |
| private_item           | tinyint(1)   | YES  |     | 0       |                |
+------------------------+--------------+------+-----+---------+----------------+

Индексы:

    mysql> show indexes from sales;
+-----------------+------------+--------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name                           | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-----------------+------------+--------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| sales |          0 | PRIMARY                            |            1 | id          | A         |      286509 |     NULL | NULL   |      | BTREE      |         |
| sales |          1 | index_sales_on_type                |            1 | type        | A         |         123 |     NULL | NULL   | YES  | BTREE      |         |
| sales |          1 | index_sales_on_buyer_id            |            1 | buyer_id    | A         |       40929 |     NULL | NULL   | YES  | BTREE      |         |
| sales |          1 | index_sales_on_merchand_id         |            1 | merchand_id | A         |       40929 |     NULL | NULL   | YES  | BTREE      |         |
| sales |          1 | index_sales_on_country_id          |            1 | country_id  | A         |           6 |     NULL | NULL   | YES  | BTREE      |         |
| sales |          1 | index_sales_on_type_and_country_id |            1 | type        | A         |         151 |     NULL | NULL   | YES  | BTREE      |         |
| sales |          1 | index_sales_on_type_and_country_id |            2 | country_id  | A         |         428 |     NULL | NULL   | YES  | BTREE      |         |
| sales |          1 | index_sales_viewed                 |            1 | buyer_id    | A         |       35813 |     NULL | NULL   | YES  | BTREE      |         |
| sales |          1 | index_sales_viewed                 |            2 | merchand_id | A         |      286509 |     NULL | NULL   | YES  | BTREE      |         |
| sales |          1 | index_sales_viewed                 |            3 | private_item| A         |      285009 |     NULL | NULL   | YES  | BTREE      |         |
| sales |          1 | index_sales_viewed                 |            4 | admin       | A         |      285009 |     NULL | NULL   | YES  | BTREE      |         |
| sales |          1 | index_sales_viewed                 |            5 | type        | A         |      285009 |     NULL | NULL   | YES  | BTREE      |         |
| sales |          1 | index_sales_viewed                 |            6 | private     | A         |      285009 |     NULL | NULL   | YES  | BTREE      |         |
| sales |          1 | index_sales_viewed                 |            7 | created_at  | A         |      285009 |     NULL | NULL   | YES  | BTREE      |         |
+-------+------------+------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

При выполнении запроса используется index_sales_on_type_and_country_id , даже если в запросе отсутствует country_id ...

Запрос занимает 2,5 секунды с этим индексом.

Но когда я использую ИСПОЛЬЗОВАТЬ ИНДЕКС (index_sales_viewed) , он уменьшается до 0,2 секунд.

Вот ОБЪЯСНЕНИЕ запроса:

+----+-------------+-----------------+------+----------------------------------------------+------+---------+------+--------+---------------------
| id | select_type | table | type  | possible_keys  | key                                | key_len | ref  | rows   | Extra                       | 
+----+-------------+-----------------+------+----------------------------------------------+------+---------+------+--------+---------------------
|  1 | SIMPLE      | sales | range |  see bellow    | index_sales_on_type_and_country_id | 258     | NULL | 208725 | Using where; Using filesort | 
+----+-------------+-----------------+------+----------------------------------------------+------+---------+------+--------+---------------------

возможные ключи:

index_sales_on_type,
index_sales_on_buyer_id,
index_sales_on_merchand_id,
index_sales_on_type_and_country_id,
index_sales_public_recent_activity

Почему MySQL по умолчанию не использует index_sales_viewed ? Может ли быть лучший индекс?

Спасибо!

1 Ответ

4 голосов
/ 02 сентября 2011

Это неправильное использование для NULL, пожалуйста, измените все столбцы, используемые в индексе, на NOT NULL

см. Это Когда использовать NULL в таблицах MySQL

официальная документация

Если этот столбец равен NULL, соответствующие индексы отсутствуют.В этом случае вы сможете улучшить производительность вашего запроса, изучив предложение WHERE, чтобы проверить, относится ли он к какому-либо столбцу или столбцам, подходящим для индексации.Если это так, создайте соответствующий индекс и снова проверьте запрос с помощью EXPLAIN

Mysql выбрал индекс index_sales_on_type_and_country_id, поскольку вы не сравниваете его со значением NULL

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