我有一个包含约 900 万条记录的表
结构
id int PK AI
pa_id int
cha_id smallint
cha_level tinyint
cha_points mediumint
cha_points_till smallint
cha_points_from medium
cha_points_date datetime
我的查询
select max(cha_points) as highest,cha_id,count(id) as entry_count,
sum(cha_points) as total_points
from playeraccounts_cha_masteries
group by cha_id
order by total_points desc
我的索引
playeraccounts_cha_masteries 0 PRIMARY 1 id A 9058483 NULL NULL BTREE
playeraccounts_cha_masteries 1 cha_id 1 cha_id A 9 NULL NULL BTREE
playeraccounts_cha_masteries 1 pa_id 1 pa_id A 156270 NULL NULL BTREE
playeraccounts_cha_masteries 1 cha_points 1 cha_points A 166100 NULL NULL BTREE
pa_id 上的索引在不同的查询中有其用途。
解释
id select_type table partitions type possible_keys key key_len ref rows filterd Extra
1 simple m null range PRIMARY,cha_id PRIMARY 4 NULL 9164555 100.00 Using where; Using temporary; Using filesort
还有什么可以加快查询速度的吗?
最佳答案
您有 3 个选择:
- 加快现有查询
在cha_id 和cha_points 字段上创建一个复合索引,将count(id) 更改为count(*) 或count(cha_id),然后再次测试。您可能需要调整索引中字段的顺序。检查是否使用了覆盖索引。
通过将 count(id) 更改为 count(*) 或 count(cha_id),您无需检查 id 列。由于您使用该计数返回每个 cha_id 组中的记录数,因此可以安全地将对 id 字段的引用替换为 * 或 cha_id。
在 cha_id 和 cha_points 字段上创建复合索引将导致覆盖索引,这意味着查询所需的所有字段都在一个索引中,因此查询不必扫描整个表。
- 创建一个单独的统计表并用触发器更新它
为 playeraccounts_cha_masteries 创建一个单独的统计表。您可以使用触发器来更新计数、最大值和总数。该页面将查询统计表而不是 playeraccounts_cha_masteries 表。此解决方案可能会减慢插入/更新/删除速度,因为每个数据修改事务都必须序列化,以便正确更新统计表。
- 创建单独的统计表并定期更新
创建一个单独的统计表,但不是使用触发器来保持它不断更新,而是使用计划作业(OS 或 mysql 级别)使用最新统计信息定期更新表。这意味着统计数据将在一段时间内不同步,但如果可以找到可接受的刷新周期,这可能是一个合理的妥协。
您甚至可以将此方法更进一步,而不是生成单独的统计表,您可以生成一个静态 html 文件,在其 header 中设置适当的到期时间和统计信息。这样服务器只需为统计数据提供静态文件。
关于Mysql sum group by performance 9M记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34940822/