我有一个看起来像这样的表:
| calls | CREATE TABLE `calls` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`request_id` int(10) unsigned NOT NULL,
`ct` int(10) unsigned DEFAULT NULL,
`wt` int(10) unsigned DEFAULT NULL,
`cpu` int(10) unsigned DEFAULT NULL,
`mu` int(10) unsigned DEFAULT NULL,
`pmu` int(10) unsigned DEFAULT NULL,
`caller_id` int(10) unsigned DEFAULT NULL,
`callee_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `caller_id` (`caller_id`,`request_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3164057 DEFAULT CHARSET=utf8 |
和一个简单的查询:
mysql> EXPLAIN SELECT
-> AVG(`c1`.`wt`) `wt`,
-> AVG(`c1`.`cpu`) `cpu`,
-> AVG(`c1`.`mu`) `mu`,
-> AVG(`c1`.`pmu`) `pmu`
-> FROM
-> `calls` `c1`;
+----+-------------+-------+------+---------------+------+---------+------+---------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------+
| 1 | SIMPLE | c1 | ALL | NULL | NULL | NULL | NULL | 3161147 | |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------+
1 row in set (0.00 sec)
mysql> SELECT
-> AVG(`c1`.`wt`) `wt`,
-> AVG(`c1`.`cpu`) `cpu`,
-> AVG(`c1`.`mu`) `mu`,
-> AVG(`c1`.`pmu`) `pmu`
-> FROM
-> `calls` `c1`;
+-----------+----------+------------+------------+
| wt | cpu | mu | pmu |
+-----------+----------+------------+------------+
| 2285.2079 | 428.2061 | 30567.4517 | 24925.7182 |
+-----------+----------+------------+------------+
1 row in set (1.61 sec)
服务器非常快(24 GB的RAM)。 my.cnf
(full my.cnf)中最相关的是:
query_cache_type=0
query_cache_size=0
key_buffer_size=50M
sort_buffer_size=10M
innodb_buffer_pool_size=1G
read_rnd_buffer_size=1M
join_buffer_size=4M
max_connections=400
table_cache=2000
table_definition_cache=2000
我可以做些什么来优化查询?只有5,278,808条记录,我似乎不太可能达到硬件限制。
我也尝试将整个表移动到另一个ENGINE=MEMORY
表。时间提高了大约30%。但是,这仍然很慢。
答案 0 :(得分:0)
您可以做的最好的短暂热量是添加一个索引,该索引将覆盖您计算的4个字段。 现在你正在进行全表扫描,如果你的索引只覆盖MySQL上面的4列,那么遍历包含你的表的所有页面的操作将转过索引,索引分开存储并包含更少的数据,因此更多的数据将适合于单页。
答案 1 :(得分:0)
您可以尝试避免一遍又一遍地查看旧数据......
也许将记录计数和求和值与上次更新的日期时间一起存储在另一个表中,并将datetime列添加到您的调用表中(确保将其编入索引)。
当您需要计算平均值时,只需查看上次检查后创建的数据,将其与新表中的数据相结合,然后更新新表。
如果你的旧数据可以更新会变得更复杂 - 那么你可能需要有触发器。