6000万条目,从某个月份中select条目。 如何优化数据库?

我有一个拥有6000万条logging的数据库。

每个条目包含:

  • ID
  • DataSourceID的
  • 一些数据
  • 约会时间

  1. 我需要从某个月份select条目。 每个月包含大约200万条目。

    select * from Entries where time between "2010-04-01 00:00:00" and "2010-05-01 00:00:00" 

    (查询大约需要1.5分钟)

  2. 我也想从给定的DataSourceID中select某个月份的数据。 (大约需要20秒)

大约有50-100个不同的DataSourceIDs。

有没有办法让这个更快? 我有什么select? 如何优化这个数据库/查询?


编辑:有约。 每秒插入60-100!

利用innodb集群主键索引。

http://dev.mysql.com/doc/refman/5.0/en/innodb-index-types.html

这将是非常高效的:

 create table datasources ( year_id smallint unsigned not null, month_id tinyint unsigned not null, datasource_id tinyint unsigned not null, id int unsigned not null, -- needed for uniqueness data int unsigned not null default 0, primary key (year_id, month_id, datasource_id, id) ) engine=innodb; select * from datasources where year_id = 2011 and month_id between 1 and 3; select * from datasources where year_id = 2011 and month_id = 4 and datasouce_id = 100; -- etc.. 

编辑2

忘记了我正在用3个月的数据运行第一个testing脚本。 这是一个月的结果:0.34和0.69秒。

 select d.* from datasources d where d.year_id = 2010 and d.month_id = 3 and datasource_id = 100 order by d.id desc limit 10; +---------+----------+---------------+---------+-------+ | year_id | month_id | datasource_id | id | data | +---------+----------+---------------+---------+-------+ | 2010 | 3 | 100 | 3290330 | 38434 | | 2010 | 3 | 100 | 3290329 | 9988 | | 2010 | 3 | 100 | 3290328 | 25680 | | 2010 | 3 | 100 | 3290327 | 17627 | | 2010 | 3 | 100 | 3290326 | 64508 | | 2010 | 3 | 100 | 3290325 | 14257 | | 2010 | 3 | 100 | 3290324 | 45950 | | 2010 | 3 | 100 | 3290323 | 49986 | | 2010 | 3 | 100 | 3290322 | 2459 | | 2010 | 3 | 100 | 3290321 | 52971 | +---------+----------+---------------+---------+-------+ 10 rows in set (0.34 sec) select d.* from datasources d where d.year_id = 2010 and d.month_id = 3 order by d.id desc limit 10; +---------+----------+---------------+---------+-------+ | year_id | month_id | datasource_id | id | data | +---------+----------+---------------+---------+-------+ | 2010 | 3 | 116 | 3450346 | 42455 | | 2010 | 3 | 116 | 3450345 | 64039 | | 2010 | 3 | 116 | 3450344 | 27046 | | 2010 | 3 | 116 | 3450343 | 23730 | | 2010 | 3 | 116 | 3450342 | 52380 | | 2010 | 3 | 116 | 3450341 | 35700 | | 2010 | 3 | 116 | 3450340 | 20195 | | 2010 | 3 | 116 | 3450339 | 21758 | | 2010 | 3 | 116 | 3450338 | 51378 | | 2010 | 3 | 116 | 3450337 | 34687 | +---------+----------+---------------+---------+-------+ 10 rows in set (0.69 sec) 

编辑1

决定testing约上述模式。 3年内有6000万行。 每个查询运行冷,即每个单独运行之后,mysql重新启动清除任何缓冲区和没有查询caching。

完整的testing脚本可以在这里find: http : //pastie.org/1723506或以下…

正如你可以看到这是一个非常高性能的架构,即使在我的谦虚桌面:)

 select count(*) from datasources; +----------+ | count(*) | +----------+ | 60306030 | +----------+ select count(*) from datasources where year_id = 2010; +----------+ | count(*) | +----------+ | 16691669 | +----------+ select year_id, month_id, count(*) as counter from datasources where year_id = 2010 group by year_id, month_id; +---------+----------+---------+ | year_id | month_id | counter | +---------+----------+---------+ | 2010 | 1 | 1080108 | | 2010 | 2 | 1210121 | | 2010 | 3 | 1160116 | | 2010 | 4 | 1300130 | | 2010 | 5 | 1860186 | | 2010 | 6 | 1220122 | | 2010 | 7 | 1250125 | | 2010 | 8 | 1460146 | | 2010 | 9 | 1730173 | | 2010 | 10 | 1490149 | | 2010 | 11 | 1570157 | | 2010 | 12 | 1360136 | +---------+----------+---------+ 12 rows in set (5.92 sec) select count(*) as counter from datasources d where d.year_id = 2010 and d.month_id between 1 and 3 and datasource_id = 100; +---------+ | counter | +---------+ | 30003 | +---------+ 1 row in set (1.04 sec) explain select d.* from datasources d where d.year_id = 2010 and d.month_id between 1 and 3 and datasource_id = 100 order by d.id desc limit 10; +----+-------------+-------+-------+---------------+---------+---------+------+---------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref |rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+------+---------+-----------------------------+ | 1 | SIMPLE | d | range | PRIMARY | PRIMARY | 4 | NULL |4451372 | Using where; Using filesort | +----+-------------+-------+-------+---------------+---------+---------+------+---------+-----------------------------+ 1 row in set (0.00 sec) select d.* from datasources d where d.year_id = 2010 and d.month_id between 1 and 3 and datasource_id = 100 order by d.id desc limit 10; +---------+----------+---------------+---------+-------+ | year_id | month_id | datasource_id | id | data | +---------+----------+---------------+---------+-------+ | 2010 | 3 | 100 | 3290330 | 38434 | | 2010 | 3 | 100 | 3290329 | 9988 | | 2010 | 3 | 100 | 3290328 | 25680 | | 2010 | 3 | 100 | 3290327 | 17627 | | 2010 | 3 | 100 | 3290326 | 64508 | | 2010 | 3 | 100 | 3290325 | 14257 | | 2010 | 3 | 100 | 3290324 | 45950 | | 2010 | 3 | 100 | 3290323 | 49986 | | 2010 | 3 | 100 | 3290322 | 2459 | | 2010 | 3 | 100 | 3290321 | 52971 | +---------+----------+---------------+---------+-------+ 10 rows in set (0.98 sec) select count(*) as counter from datasources d where d.year_id = 2010 and d.month_id between 1 and 3; +---------+ | counter | +---------+ | 3450345 | +---------+ 1 row in set (1.64 sec) explain select d.* from datasources d where d.year_id = 2010 and d.month_id between 1 and 3 order by d.id desc limit 10; +----+-------------+-------+-------+---------------+---------+---------+------+---------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref |rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+------+---------+-----------------------------+ | 1 | SIMPLE | d | range | PRIMARY | PRIMARY | 3 | NULL |6566916 | Using where; Using filesort | +----+-------------+-------+-------+---------------+---------+---------+------+---------+-----------------------------+ 1 row in set (0.00 sec) select d.* from datasources d where d.year_id = 2010 and d.month_id between 1 and 3 order by d.id desc limit 10; +---------+----------+---------------+---------+-------+ | year_id | month_id | datasource_id | id | data | +---------+----------+---------------+---------+-------+ | 2010 | 3 | 116 | 3450346 | 42455 | | 2010 | 3 | 116 | 3450345 | 64039 | | 2010 | 3 | 116 | 3450344 | 27046 | | 2010 | 3 | 116 | 3450343 | 23730 | | 2010 | 3 | 116 | 3450342 | 52380 | | 2010 | 3 | 116 | 3450341 | 35700 | | 2010 | 3 | 116 | 3450340 | 20195 | | 2010 | 3 | 116 | 3450339 | 21758 | | 2010 | 3 | 116 | 3450338 | 51378 | | 2010 | 3 | 116 | 3450337 | 34687 | +---------+----------+---------------+---------+-------+ 10 rows in set (1.98 sec) 

希望这可以帮助 :)

要在某个特定的月份,特定年份,更快地获得条目 – 您需要索引time列 :

 CREATE INDEX idx_time ON ENTRIES(time) USING BTREE; 

另外,使用:

 SELECT e.* FROM ENTRIES e WHERE e.time BETWEEN '2010-04-01' AND DATE_SUB('2010-05-01' INTERVAL 1 SECOND) 

…因为BETWEEN是包容性的,所以你会发现任何date“2010-05-01 00:00:00”与您张贴的查询。

我也想从给定的DataSourceID中select某个月份的数据

您可以为datasourceid列添加单独的索引:

 CREATE INDEX idx_time ON ENTRIES(datasourceid) USING BTREE; 

…或者设置一个覆盖索引来包含两列:

 CREATE INDEX idx_time ON ENTRIES(time, datasourceid) USING BTREE; 

覆盖索引要求在查询中使用最左边的列。 在这个例子中,有time第一次将适用于你提到的两种情况 – datasourceid不必用于索引的使用。 但是,您必须通过查看EXPLAIN输出来testing您的查询,才能真正了解哪些数据最适合您的数据和查询。

也就是说,索引将减慢INSERT,UPDATE和DELETE语句。 而且,如果列数据具有几乎不同的值,那么索引不会提供很多值 – IE:由于基数很低,因此布尔列是索引的不好select。

您可以使用索引来交换查询速度的磁盘使用情况。 开始time列的索引可以加速询问特定月份的查询:

 create index IX_YourTable_Date on YourTable (time, DataSourceID, ID, SomeData) 

由于索引从time字段开始,因此MySQL可以对索引执行键范围扫描。 这应该是尽可能快的。 索引应包含查询中的所有列,否则MySQL将不得不从索引中查找每行的表数据。 既然你要求200万行,MySQL可能会忽略一个没有覆盖的索引。 (覆盖索引=包含查询中所有行的索引。)

如果您从不查询ID,则可以重新定义要使用的表(time, DataSourceID, ID)作为主键:

 alter table YourTable add primary key (time, DataSourceID, ID) 

这将会在磁盘空间中不花费任何time加快search速度,但在IDsearch会非常缓慢。

如果你还没有在时间领域,我会尝试把一个索引。

对于DataSourceID,您可以尝试使用Enum而不是varchar / int。