一尘不染

如何通过“分组依据”和“位置”加快“选择计数(*)”?

mysql

如何加快select count(*)group by
它太慢并且经常使用。
我用很大的麻烦select count(*),并group by具有300多万行的表。

select object_title,count(*) as hot_num   
from  relations 
where relation_title='XXXX'   
group by object_title

Relation_titleobject_title 为varchar。 其中Relation_title =’XXXX’
,返回超过1,000,000行,导致 object_title 上的索引 无法正常工作。


阅读 202

收藏
2020-05-17

共1个答案

一尘不染

为了提高难度,我尝试了以下几种方法:

(更轻松) - 确保您具有正确的覆盖指数

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查询知道该归一化,但可以不理会SELECTs 。

(最困难)-散列字符串列并为哈希索引

如果规范化意味着更改太多代码,但是您可以稍微更改架构,则可能要考虑为字符串列创建128位哈希(使用MD5函数)。在这种情况下(与规范化不同),您不必更改所有查询,而只需更改INSERT和某些SELECT。无论如何,您将需要对字符串字段进行哈希处理,然后在哈希表上创建索引,例如

CREATE INDEX ix_temp ON relations (relation_title_hash, object_title_hash);

请注意,您将需要使用SELECT来确保通过哈希索引进行计算,而不要拉入聚集索引(需要解析object_title的实际文本值才能满足查询)。

另外,如果relationship_title具有较小的varchar大小,但对象标题具有较大的大小,则可能仅散列object_title并在上创建索引(relation_title, object_title_hash)

请注意,仅当这些字段中的一个或两个相对于哈希值的大小很长时,此解决方案才有用。

还要注意,由于小写字符串的哈希值与大写字符串的哈希值不同,因此哈希值会引起有趣的区分大小写/排序规则的影响。因此,您需要确保对字符串进行规范化之后再对它们进行哈希处理-
换句话说,如果您在不区分大小写的数据库中,则仅对小写字母进行哈希处理。您还可能需要从头或尾开始修剪空格,具体取决于数据库处理前导/尾随空格的方式。

2020-05-17