Mysql查询优化多列索引解决了这个慢的问题?

时间:2013-08-25 06:08:57

标签: php mysql indexing

+----------------------------+------------------------------------------------------------------------------+------+-----+---------+----------------+
| Field                      | Type                                                                         | Null | Key | Default | Extra          |
+----------------------------+------------------------------------------------------------------------------+------+-----+---------+----------------+
| type                       | enum('Website','Facebook','Twitter','Linkedin','Youtube','SeatGeek','Yahoo') | NO   | MUL | NULL    |                |
| name                       | varchar(100)                                                                 | YES  | MUL | NULL    |                |
| processing_interface_id    | bigint(20)                                                                   | YES  | MUL | NULL    |                |
| processing_interface_table | varchar(100)                                                                 | YES  | MUL | NULL    |                |
| create_time                | datetime                                                                     | YES  | MUL | NULL    |                |
| run_time                   | datetime                                                                     | YES  | MUL | NULL    |                |
| completed_time             | datetime                                                                     | YES  | MUL | NULL    |                |
| reserved                   | int(10)                                                                      | YES  | MUL | NULL    |                |
| params                     | text                                                                         | YES  |     | NULL    |                |
| params_md5                 | varchar(100)                                                                 | YES  | MUL | NULL    |                |
| priority                   | int(10)                                                                      | YES  | MUL | NULL    |                |
| id                         | bigint(20) unsigned                                                          | NO   | PRI | NULL    | auto_increment |
| status                     | varchar(40)                                                                  | NO   | MUL | none    |                |
+----------------------------+------------------------------------------------------------------------------+------+-----+---------+----------------+

select *  from remote_request use index ( processing_order )  where remote_request.status = 'none' and type = 'Facebook' and reserved = '0' order by priority desc limit 0, 40;

此表接收极大量的写入和读取。每个remote_request最终都是一个进程,它可以在0到5个其他remote_requests之间产生任何地方,具体取决于请求的类型和请求的作用。

该表目前约有350万条记录,当网站本身处于高负荷状态时,它会进入蜗牛节目,并且我有超过50个或更多的实例同时运行。 (如果你不确定的话,REST请求就是表的目的。)

随着桌子的增长,它变得越来越糟。我可以每天清除处理过的请求,但最终这并不能解决问题。

我需要的是此查询始终具有非常低的响应率。

以下是表格中的当前索引。

+----------------+------------+----------------------------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table          | Non_unique | Key_name                         | Seq_in_index | Column_name                | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------------+------------+----------------------------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| remote_request |          0 | PRIMARY                          |            1 | id                         | A         |     2403351 |     NULL | NULL   |      | BTREE      |         |               |
| remote_request |          1 | type_index                       |            1 | type                       | A         |          18 |     NULL | NULL   |      | BTREE      |         |               |
| remote_request |          1 | processing_interface_id_index    |            1 | processing_interface_id    | A         |          18 |     NULL | NULL   | YES  | BTREE      |         |               |
| remote_request |          1 | processing_interface_table_index |            1 | processing_interface_table | A         |          18 |     NULL | NULL   | YES  | BTREE      |         |               |
| remote_request |          1 | create_time_index                |            1 | create_time                | A         |      160223 |     NULL | NULL   | YES  | BTREE      |         |               |
| remote_request |          1 | run_time_index                   |            1 | run_time                   | A         |      343335 |     NULL | NULL   | YES  | BTREE      |         |               |
| remote_request |          1 | completed_time_index             |            1 | completed_time             | A         |      267039 |     NULL | NULL   | YES  | BTREE      |         |               |
| remote_request |          1 | reserved_index                   |            1 | reserved                   | A         |          18 |     NULL | NULL   | YES  | BTREE      |         |               |
| remote_request |          1 | params_md5_index                 |            1 | params_md5                 | A         |     2403351 |     NULL | NULL   | YES  | BTREE      |         |               |
| remote_request |          1 | priority_index                   |            1 | priority                   | A         |         716 |     NULL | NULL   | YES  | BTREE      |         |               |
| remote_request |          1 | status_index                     |            1 | status                     | A         |          18 |     NULL | NULL   |      | BTREE      |         |               |
| remote_request |          1 | name_index                       |            1 | name                       | A         |          18 |     NULL | NULL   | YES  | BTREE      |         |               |
| remote_request |          1 | processing_order                 |            1 | priority                   | A         |         200 |     NULL | NULL   | YES  | BTREE      |         |               |
| remote_request |          1 | processing_order                 |            2 | status                     | A         |         200 |     NULL | NULL   |      | BTREE      |         |               |
| remote_request |          1 | processing_order                 |            3 | type                       | A         |         200 |     NULL | NULL   |      | BTREE      |         |               |
| remote_request |          1 | processing_order                 |            4 | reserved                   | A         |         200 |     NULL | NULL   | YES  | BTREE      |         |               |
+----------------+------------+----------------------------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

知道我怎么解决这个问题?是不是可以制作某种复杂的索引,它会自动优先排序它们,然后选择匹配'Facebook'类型的前40个?它目前正在扫描超过500k行的表,然后返回一个非常低效的结果。

我一直在修改的其他一些版本的查询是:

select *  from remote_request use index ( type_index,status_index,reserved_index,priority_index )  where remote_request.status = 'none' and type = 'Facebook' and reserv                          ed = '0' order by priority desc limit 0, 40

如果我们能够将扫描的行扫描到1000行以下,这将是惊人的,具体取决于有多少类型的请求进入表格。

先谢谢,除了最有经验的mysql专家外,对于大多数人来说,这可能是一个真正的胡桃夹子?

2 个答案:

答案 0 :(得分:1)

这不是一个完整的答案,但评论太长了:

您实际上是在搜索所有这些索引吗?如果没有摆脱一些。额外的索引减慢了写入速度

其次在查询中使用EXPLAIN,并且在执行时不指定索引。了解MySQL如何处理它而不是强制选择(通常它做正确的事情)。

最后排序可能会给你带来最大的伤害。如果你不排序它可能很快得到记录。它必须扫描并排序符合条件的每一行,然后才能返回前40名。

选项:

  1. 尝试创建一个VIEW(不熟悉VIEWS但它可能有用)
  2. 将此表拆分为较小的表
  3. 使用第三方工具,例如 Sphinx或Lucene创建专门的索引来搜索。 (我有 之前使用Sphinx之类的东西。你可以找到它 http://sphinxsearch.com/)。
  4. 或者考虑使用NoSQL解决方案,您可以使用Map函数来执行此操作。
  5. 编辑我读了一些关于使用VIEW的内容,我不认为它会对你的情况有所帮助,因为你有这么大的表。请参阅此主题中的答案:Using MySQL views to increase performance

答案 1 :(得分:1)

您的四列索引具有正确的列,但顺序错误。

您希望索引首先查找匹配的行,您可以通过三列来查找。您正在查找三个相等条件,因此您知道一旦索引找到匹配行的集合,这些行的顺序基本上与前三列相关。因此,要解决这种关系,请将第四列添加到您想要排序的列。

如果你这样做,那么ORDER BY就变成了无操作,因为查询只能按照它们存储在索引中的顺序读取行。

所以我会创建以下索引:

CREATE INDEX processing_order2 ON remote_request 
 (status, type, reserved, priority);

对前三列的顺序可能没有多大意义,因为它们都与AND结合在一起。但priority列属于最后一行。

您可能还想阅读我的演示文稿How to Design Indexes, Really

顺便说一句,如果您拥有正确的索引,则不需要使用USE INDEX(),MySQL的优化程序将在大多数情况下自动选择它。但是USE INDEX()可以阻止优化器考虑您创建的新索引,因此它对代码维护来说是一个缺点。