我有一张比特币交易表:
CREATE TABLE `transactions` ( `trans_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `trans_exchange` int(10) unsigned DEFAULT NULL, `trans_currency_base` int(10) unsigned DEFAULT NULL, `trans_currency_counter` int(10) unsigned DEFAULT NULL, `trans_tid` varchar(20) DEFAULT NULL, `trans_type` tinyint(4) DEFAULT NULL, `trans_price` decimal(15,4) DEFAULT NULL, `trans_amount` decimal(15,8) DEFAULT NULL, `trans_datetime` datetime DEFAULT NULL, `trans_sid` bigint(20) DEFAULT NULL, `trans_timestamp` int(10) unsigned DEFAULT NULL, PRIMARY KEY (`trans_id`), KEY `trans_tid` (`trans_tid`), KEY `trans_datetime` (`trans_datetime`), KEY `trans_timestmp` (`trans_timestamp`), KEY `trans_price` (`trans_price`), KEY `trans_amount` (`trans_amount`) ) ENGINE=MyISAM AUTO_INCREMENT=6162559 DEFAULT CHARSET=utf8;
从AUTO_INCREMENT值可以看出,该表有超过600万个条目。最终会有更多。
我想查询表格,以获得在任意时间间隔内交易的最高价格,最低价格,交易量和总金额。为此,我使用了这样的查询:
SELECT DATE_FORMAT( MIN(transactions.trans_datetime), '%Y/%m/%d %H:%i:00' ) AS trans_datetime, SUM(transactions.trans_amount) as trans_volume, MAX(transactions.trans_price) as trans_max_price, MIN(transactions.trans_price) as trans_min_price, COUNT(transactions.trans_id) AS trans_count FROM transactions WHERE transactions.trans_datetime BETWEEN '2014-09-14 00:00:00' AND '2015-09-13 23:59:00' GROUP BY transactions.trans_timestamp DIV 86400
这应该选择一年内完成的交易,按天(86,400秒)分组。
这个想法是timestamp字段,它包含与datetime相同的值,但作为时间戳...我发现这比UNIX_TIMESTAMP(trans_datetime)更快,除以我希望在时间间隔内的秒数
问题:查询速度很慢。我的处理时间超过4秒。以下是EXPLAIN的结果:
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE transactions ALL trans_datetime,trans_timestmp NULL NULL NULL 6162558 Using where; Using temporary; Using filesort
问题:是否可以更好地优化它?这种结构或方法是否有缺陷?我尝试了几种方法,并且只取得了适度的毫秒级增益。
答案 0 :(得分:0)
表中的大多数数据是过去12个月的数据?所以你需要触摸大部分桌子?然后没有办法加速 查询。但是,您可以更快地获得相同的输出数量级......
创建摘要表。它将DATE
作为PRIMARY KEY
,而列将有效地显示在SELECT
中提到的字段。
最初填充汇总表后,通过每天为当天的交易添加新行来维护它。 More in my blog
然后获取所需输出的查询将命中此摘要表(仅有几百行),而不是具有数百万或行的表。