2

我有一个看起来像这样的表:

| 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完整的 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%。但是,这仍然很慢。

4

2 回答 2

0

您可以做的最好的短期事情是添加一个索引,该索引将涵盖您计算的 4 个字段。现在您正在执行全表扫描,如果您创建一个仅覆盖 MySQL 上方 4 列的索引,则遍历包含您的表的所有页面的操作将遍历索引,索引单独存储并且包含更少的数据,因此更多的数据将适合单页。

于 2012-09-19T19:37:17.453 回答
0

您可以尝试避免一遍又一遍地查看旧数据...

也许将记录计数和总和值与上次更新的日期时间一起存储在另一个表中,并将日期时间列添加到您的调用表中(确保它被索引)。

当您需要计算平均值时,只需查看上次检查后创建的数据,将其与新表中的数据结合,然后更新新表。

如果您的旧数据可以更新,它会变得更加复杂 - 您可能需要有触发器。

于 2012-09-19T22:34:14.050 回答