MySQL性能问题/查询速度慢,数据量大

MySQL性能问题/查询速度慢,数据量大,mysql,query-optimization,Mysql,Query Optimization,MySql 我有一个查询需要花费一些时间才能加载到一个表中,名为impressionthat 大约有5700万行。下表定义: +-----------------+--------------+------+-----+ | Field | Type | Null | Key | +-----------------+--------------+------+-----+ | id | int(11) | NO | P

MySql

我有一个查询需要花费一些时间才能加载到一个表中,名为
impression
that 大约有5700万行。下表定义:

+-----------------+--------------+------+-----+
| Field           | Type         | Null | Key |
+-----------------+--------------+------+-----+
| id              | int(11)      | NO   | PRI |
| data_type       | varchar(16)  | NO   | MUL |
| object_id       | int(11)      | YES  |     |
| user_id         | int(11)      | YES  |     |
| posted          | timestamp    | NO   | MUL |
| lat             | float        | NO   |     |
| lng             | float        | NO   |     |
| region_id       | int(11)      | NO   |     |
+-----------------+--------------+------+-----+
表中的索引为:

+------------+------------+----------+--------------+-------------+
| Table      | Non_unique | Key_name | Seq_in_index | Column_name |
+------------+------------+----------+--------------+-------------+
| impression |          0 | PRIMARY  |            1 | id          |
| impression |          1 | posted   |            1 | posted      |
| impression |          1 | oi_dt    |            1 | data_type   |
| impression |          1 | oi_dt    |            2 | object_id   |
+------------+------------+----------+--------------+-------------+
典型的select语句如下所示:

SELECT COUNT(`id`)
FROM `impression`
WHERE 
  posted BETWEEN DATE('2014-01-04') AND DATE('2014-06-01')
  AND `data_type` =  'event'
  AND `object_id` IN ('1', '2', '3', '4', '5', '8', ...)
…典型的记录如下所示(按上述模式的顺序):

此语句运行大约需要26秒,这就是问题所在 谎言这里是否可以采用任何解决方案来减少这一时间 低于现在的水平?理想情况下为<1秒

我愿意切换存储解决方案/等。。。在这一点上任何有帮助的事情。 非常感谢你的帮助

其他可能值得注意的事情:

  • 该表正在使用InnoDB存储引擎
  • 使用MySQL 5.5
  • 服务器:运行CentOS 6的8Gb RAM(机架空间)

MySQL通常在给定查询中每个表只使用一个索引。您在发布的
上有一个索引
,在
数据类型
对象id
上有一个复合索引

您应该使用EXPLAIN找出查询当前使用的索引。EXPLAIN还将告诉您它估计将检查多少行以生成结果集(它可能会检查更多行,而不是将其放入最终结果)

列应按以下顺序排列:

  • 相等条件中的列,例如查询中的
    data\u type='event'

  • 列在范围条件或排序中,但只能得到一个这样的列。处于范围条件或排序中的后续列不会从添加到第一列之后的索引中获得任何好处。因此,选择最有选择性的列,也就是说,您的条件将搜索范围缩小到表的较小子集

  • 选择列表中的其他列,如果您只有几个这样的列,并且希望获得覆盖索引效果。如果使用InnoDB,则不必添加主键列,因为每个辅助索引都会自动在右端包含主键列,即使您没有声明

  • 因此,在您的情况下,最好在
    数据类型
    发布
    上建立索引。试试看,然后用解释来确认。这取决于您提供的日期范围是否比对象id列表更具选择性


    另请参见我的演示。

    MySQL通常在给定查询中每个表只使用一个索引。您在发布的
    上有一个索引
    ,在
    数据类型
    对象id
    上有一个复合索引

    您应该使用EXPLAIN找出查询当前使用的索引。EXPLAIN还将告诉您它估计将检查多少行以生成结果集(它可能会检查更多行,而不是将其放入最终结果)

    列应按以下顺序排列:

  • 相等条件中的列,例如查询中的
    data\u type='event'

  • 列在范围条件或排序中,但只能得到一个这样的列。处于范围条件或排序中的后续列不会从添加到第一列之后的索引中获得任何好处。因此,选择最有选择性的列,也就是说,您的条件将搜索范围缩小到表的较小子集

  • 选择列表中的其他列,如果您只有几个这样的列,并且希望获得覆盖索引效果。如果使用InnoDB,则不必添加主键列,因为每个辅助索引都会自动在右端包含主键列,即使您没有声明

  • 因此,在您的情况下,最好在
    数据类型
    发布
    上建立索引。试试看,然后用解释来确认。这取决于您提供的日期范围是否比对象id列表更具选择性


    另请参阅我的演示。

    不确定这是否是一个可行的解决方案,但分区可能会加快速度。我有一个类似的印象表,并发现下面的帮助很大。不过,我主要是在当天查询

    ALTER TABLE impression PARTITION BY RANGE(TO_DAYS(posted))(
      PARTITION beforeToday VALUES LESS THAN(735725),
      PARTITION today       VALUES LESS THAN(735726),
      PARTITION future      VALUES LESS THAN MAXVALUE
    );
    

    这确实需要一些维护(必须经常更新以获得好处)。如果您希望查询范围更广,我认为需要更少的维护。

    不确定这对您来说是否是一个可行的解决方案,但分区可能会加快速度。我有一个类似的印象表,并发现下面的帮助很大。不过,我主要是在当天查询

    ALTER TABLE impression PARTITION BY RANGE(TO_DAYS(posted))(
      PARTITION beforeToday VALUES LESS THAN(735725),
      PARTITION today       VALUES LESS THAN(735726),
      PARTITION future      VALUES LESS THAN MAXVALUE
    );
    

    这确实需要一些维护(必须经常更新以获得好处)。如果您希望查询更广泛的范围,我认为需要较少的维护。

    Bill,感谢您的快速回复。我知道这不是我第一次在我的回答中看到你的脸:)比尔,谢谢你的快速回复。我知道这不是我第一次在我的回答中看到你的脸:)1。去掉in()1中的倒逗号。去掉in()中的倒逗号