索引查询"WHERE IN(1,2,3)AND b = 4"

Mat*_*chu 0 mysql sql indexing ruby-on-rails

我正在尝试应用一个索引来加速我的应用程序中最慢的查询之一:

SELECT * FROM orders WHERE product_id IN (1, 2, 3, 4) AND user_id = 5678;
Run Code Online (Sandbox Code Playgroud)

我有一个索引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 |
+----+-------------+--------+------+-------------------------------------------------------------------------------------------+------+---------+------+------+-------------+
Run Code Online (Sandbox Code Playgroud)

(在开发中只有6行,所以无论如何,但是在生产中大约有400k行,因此执行大约需要0.25秒,并且这个查询经常被解雇.)

我怎么能避免WHERE这里的简单?我想我可以为每个发送查询product_id,这可能比这个版本更快,但产品的数量可能非常高,所以如果它在一个查询中是可行的,那将是非常可取的.这个查询是由Rails生成的,所以我对可以重构查询本身的程度有点限制.谢谢!

Bra*_*vic 5

为了获得最佳性能这一特定查询您的生产表(400K与行),你需要在一个综合指数{user_id, product_id},中的顺序.

理想情况下,这将是唯一的索引,您将使用InnoDB,因此表是集群的.每个附加索引在修改数据时都会受到惩罚,并且在集群表中的二级索引之上甚至比基于堆的表中的二级索引更昂贵.

要了解为什么user_id(而不是product_id)应该处于指数的前沿,请查看指数剖析.实质上,由于WHERE只搜索一个user_id,因此首先将相关product_id值聚集在索引中更近的位置.

(它{product_id, user_id}也可以工作,但会"分散""目标"索引节点不太有利.)