MySQL性能问题/缓慢查询大量数据

时间:2014-05-13 21:39:11

标签: mysql query-optimization

MySQL的

我的查询需要一些时间来加载一个名为impression的表 有大约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', ...)

...并且典型的记录看起来像(按照上面的架构顺序):

'event', 1234, 81, '2014-01-02 00:00:01', 35.3, -75.2, 10

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

我愿意切换存储解决方案/等等......这些都有帮助。 非常感谢您的帮助。

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

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

2 个答案:

答案 0 :(得分:4)

MySQL通常在给定查询中每个表只使用一个索引。您有posted的索引和data_type上的复合索引,object_id

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

列应按此顺序排列:

  1. 相等条件中的列,例如在您的查询中data_type = 'event'

  2. 范围条件中的列或排序,但您只能获得一个此类列。处于范围条件或排序的后续列不会从第一个此类列之后添加到索引中获益。因此,选择最具选择性的列,也就是说,您的条件会将搜索范围缩小到表格的较小子集。

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

  4. 因此,在您的情况下,使用data_typeposted上的索引可能会更好。尝试并使用EXPLAIN进行确认。这取决于您提供的日期范围是否比object_id列表更具选择性。

    另见我的演讲How to Design Indexes, Really

答案 1 :(得分:0)

不确定这是否适合您,但分区可能会加快速度。我有一个类似的印象表,并找到了以下帮助它。我现在主要在当天查询。

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
);

这确实会产生一些维护(必须经常更新才能获得好处)。如果您希望在更广泛的范围内进行查询,我认为需要的维护更少。