Mysql 如何优化平均查询表?
我有一张这样的桌子:Mysql 如何优化平均查询表?,mysql,sql,indexing,Mysql,Sql,Indexing,我有一张这样的桌子: | 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,
| 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)
服务器速度非常快(24GB内存)。最相关的my.cnf
()是:
我可以做些什么来优化查询吗?由于只有5278808条记录,我似乎不太可能达到硬件限制
我还尝试将整个表移动到另一个相同的
ENGINE=MEMORY
表中。时间大约缩短了30%。但是,这仍然很慢。你能做的最好的简短的therm事情是添加一个涵盖你计算的4个字段的索引。
现在,您正在执行一个完整的表扫描操作,如果您在MySQL上创建一个只覆盖4列的索引,则遍历包含表的所有页面将遍历索引,该索引单独存储,并且包含较少的数据,以便在单个页面中容纳更多的数据 你能做的最好的简短的事情就是添加一个索引,它将覆盖你计算的4个字段。
现在,您正在执行一个完整的表扫描操作,如果您在MySQL上创建一个只覆盖4列的索引,则遍历包含表的所有页面将遍历索引,该索引单独存储,并且包含较少的数据,以便在单个页面中容纳更多的数据 您可以尝试避免反复查看旧数据 可能会将记录计数和求和值与上次更新的日期时间一起存储在另一个表中,并在calls表中添加一个datetime列(确保它已被索引) 当您需要计算平均值时,只需查看上次检查后创建的数据,将其与新表中的数据合并,然后更新新表
如果您的旧数据可以更新,它会变得更加复杂-您可能需要有触发器。您可以尝试避免反复查看旧数据 可能会将记录计数和求和值与上次更新的日期时间一起存储在另一个表中,并在calls表中添加一个datetime列(确保它已被索引) 当您需要计算平均值时,只需查看上次检查后创建的数据,将其与新表中的数据合并,然后更新新表
如果您的旧数据可以更新,它会变得更加复杂-您可能需要有触发器。是否可以在其他表的单个记录上有一个“实时总和”,并在“calls”表上使用更新/删除/插入TIRGER来保持它的准确性???您能解决您的问题吗?还是你找到了解决办法?请在此分享;)@LuisSiquot,我并没有真正解决这个问题。我的变通方法对大多数观众没有用处。然而,我最终使用了带有
ENGINE=MEMORY
的临时表。我的主要问题不是查询需要300毫秒(或任何其他大的数字),而是每次脚本运行时,我必须以不同的方式对数据进行排序/分组,发出5次或更多次此查询。将感兴趣的数据集聚合到一个临时内存表中,帮助我将页面加载时间缩短了80%+。是否可以在另一个表的单个记录上有一个“实时总和”,并通过“调用”表上的更新/删除/插入TIRGER来保持它的准确性???您能解决您的问题吗?还是你找到了解决办法?请在此分享;)@LuisSiquot,我并没有真正解决这个问题。我的变通方法对大多数观众没有用处。然而,我最终使用了带有ENGINE=MEMORY
的临时表。我的主要问题不是查询需要300毫秒(或任何其他大的数字),而是每次脚本运行时,我必须以不同的方式对数据进行排序/分组,发出5次或更多次此查询。将感兴趣的数据集聚合到一个临时内存表中帮助我将页面加载时间缩短了80%+。我不这么认为,这不是I/O问题,这里的问题是总结这么多数据。请避免“查看我的更新anwser”,因为OP无论如何都会收到通知。出于好奇,我创建了一个只包含相关列的新表–差异(如果有)微不足道。您如何确定这不是I/O问题?你没有足够的信息来了解这一点。你也可以尝试用你最喜欢的语言计算5m数字的平均值,你会发现它会非常快。@MichaelT如果我最喜欢的语言是PHP怎么办?:-)无论如何,这是离题的。@伙计,你现在应该将innodb_buffer_pool_大小增加到可用内存的80%,你只使用可用内存的一小部分,还要尝试测量你的查询,是的,即使PHP在这项任务中也会很快。我不这么认为,这不是I/O问题,这里的问题是总结这么多数据。请避免“查看我的更新anwser”,因为OP无论如何都会收到通知。出于好奇,我创建了一个只包含相关列的新表–差异(如果有)微不足道。您如何确定这不是I/O问题?你没有足够的信息来了解这一点。你也可以尝试用你最喜欢的语言计算5m数字的平均值,你会发现它会非常快。@MichaelT如果我最喜欢的语言是PHP怎么办?:-)无论如何,这是离题的。@伙计,你现在应该将innodb_buffer_pool_大小增加到可用内存的80%,你只需要使用可用内存的一小部分,还要尝试测量你的查询,是的,即使是PHP在这项任务中也会很快
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