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的8Gb RAM(机架空间)
最佳答案
MySQL通常在给定查询中每个表仅使用一个索引。您在posted
上有一个索引,在data_type
,object_id
上有一个复合索引。
您应该使用EXPLAIN来查找查询当前正在使用的索引。 EXPLAIN还将告诉您它估计将检查多少行以产生结果集(它可能检查的行多于最终结果的行数)。
列应按以下顺序:
相等条件下的列,例如查询data_type = 'event'
中的列
范围条件或排序中的列,但您只能得到一个这样的列。处于范围条件或排序中的后续列不会因从第一个此类列之后添加到索引中而获得任何好处。因此,选择最有选择性的列,即您的条件将搜索范围缩小到表的较小子集。
选择列表中的其他列(如果您只有几个这样的列,并且您希望获得覆盖索引效果)。如果使用InnoDB,则不必添加主键列,因为每个二级索引都会在右端自动包括主键列,即使您没有声明也是如此。
因此,根据您的情况,使用data_type
,posted
上的索引可能会更好。尝试一下,然后使用EXPLAIN进行确认。这取决于您提供的日期范围是否比object_id的列表更具选择性。
另请参阅我的演示文稿How to Design Indexes, Really。