Mysql “如何加速”;选择“计数(*)”;加上;分组方式;及;“在哪里?”;?

Mysql “如何加速”;选择“计数(*)”;加上;分组方式;及;“在哪里?”;?,mysql,performance,indexing,count,group-by,Mysql,Performance,Indexing,Count,Group By,如何使用分组依据加快选择计数(*)? 速度太慢,使用频率很高。 我在使用select count(*)和groupby时遇到了一个很大的问题,因为表中有超过3000000行 select object_title,count(*) as hot_num from relations where relation_title='XXXX' group by object_title 关系\标题,对象\标题为varchar。 其中返回超过1000000行的关系\u title=

如何使用
分组依据加快
选择计数(*)

速度太慢,使用频率很高。
我在使用
select count(*)
groupby
时遇到了一个很大的问题,因为表中有超过3000000行

select object_title,count(*) as hot_num   
from  relations 
where relation_title='XXXX'   
group by object_title  
关系\标题对象\标题为varchar。
其中返回超过1000000行的关系\u title='XXXX'导致对象\u title上的索引无法正常工作。

有一点您确实需要 更多的RAM/CPU/IO。你的硬件可能已经达到了这一点

我会注意到使用索引通常是无效的(除非它们是 覆盖)用于命中表中总行数1-2%以上的查询。 如果您的大型查询正在进行索引查找和书签查找,则可能是 因为缓存的计划只来自一天的总查询。尝试添加 在WITH(INDEX=0)中,强制执行表格扫描并查看是否更快

这是从:

如果您想知道整个表的大小,应该查询元表或信息模式(我知道的每个DBMS上都有,但我不确定MySQL)。如果你的查询是选择性的,你必须确保有一个索引


好了,您已经无能为力了。

首先要尝试使用复合索引为GROUPBY子句中的列编制索引。这样的查询可能只使用索引数据来回答,根本不需要扫描表。由于索引中的记录已排序,DBMS不需要作为组处理的一部分执行单独的排序。但是,索引会减慢表的更新速度,因此,如果您的表经历了大量更新,请谨慎使用

如果将InnoDB用于表存储,则表的行将通过主键索引进行物理聚集。如果这(或其中的前导部分)恰好与您的组按键匹配,那么应该会加快这样的查询,因为相关记录将一起检索。同样,这避免了必须执行单独的排序

一般来说,位图索引是另一种有效的替代方法,但据我所知,MySQL目前不支持这些索引

物化视图是另一种可能的方法,但MySQL也不直接支持这种方法。但是,如果不要求计数统计信息是完全最新的,则可以定期运行
CREATE TABLE。。。按SELECT…
语句手动缓存结果。这有点难看,因为它不是透明的,但在您的情况下可能是可以接受的

您还可以使用触发器维护逻辑级缓存表。此表将为GROUPBY子句中的每一列提供一列,并带有一个Count列,用于存储特定分组键值的行数。每次在基表中添加或更新行时,在摘要表中插入或递增/递减该特定分组键的计数器行。这可能比伪物化视图方法更好,因为缓存的摘要始终是最新的,并且每次更新都是增量完成的,对资源的影响应该较小。但是,我认为您必须注意缓存表上的锁争用。

如果您有InnoDB,count(*)和任何其他聚合函数将执行表扫描。我在这里看到了一些解决方案:

  • 使用触发器并将聚合存储在单独的表中。优点:正直。缺点:更新速度慢
  • 使用处理队列。优点:快速更新。缺点:在处理队列之前,旧状态可能会一直存在,因此用户可能会感到缺乏完整性
  • 完全分离存储访问层,并将聚合存储在单独的表中。存储层将了解数据结构,并可以应用增量,而不是进行完整计数。例如,如果您在其中提供“addObject”功能,您将知道何时添加了对象,因此聚合将受到影响。然后只执行一次
    更新表集count=count+1
    。优点:更新速度快,完整性好(如果多个客户端可以更改同一条记录,您可能需要使用锁)。缺点:您需要结合一些业务逻辑和存储
  • 试验 计数(myprimaryindexcolumn)
    并将性能与您的计数(*)进行比较。

    根据难度的增加,我将尝试以下几点:

    (更简单)-确保您拥有正确的覆盖指数

    CREATE INDEX ix_temp ON relations (relation_title, object_title);
    
    考虑到您现有的模式,这将使性能最大化,因为(除非您的mySQL优化器版本真的很愚蠢!)它将最小化满足查询所需的I/O数量(不像索引按相反顺序扫描整个索引)它将覆盖查询,因此您不必接触聚集索引

    (稍微难一点)-确保varchar字段尽可能小

    MySQL上varchar索引的性能挑战之一是,在处理查询时,字段的完整声明大小将被拉入RAM。因此,如果您有一个varchar(256),但只使用4个字符,那么在处理查询时,您仍然需要支付256字节的RAM使用量。哎哟因此,如果您可以轻松地缩小varchar限制,这将加快您的查询速度

    (更难)-正常化

    30%的行只有一个字符串值,这显然是要求将其规范化为另一个表,这样就不会重复字符串数百万次。考虑规范化为三个表,并使用整数ID加入它们。 在某些情况下,您可以在封面下进行规范化,并使用与当前表名称匹配的视图隐藏规范化。。。然后,您只需要让INSERT/UPDATE/DELETE查询知道规范化,但可以保留SELECT
    CREATE INDEX ix_temp ON relations (relation_title_hash, object_title_hash);
    
    CREATE INDEX ix_temp ON relations (relation_title, object_title);