如何在执行COUNT(*)GROUP BY字符串时实现绝对最快的方式

时间:2015-09-13 00:06:49

标签: mysql sql

我将拥有一个相对较大的增长数据集,其中250M +行具有非常基本的表结构:

id (unsigned int primary)age (tinyint)email (some type of string)

我将根据count(*)分组的age执行email次查询。例如:

select count(*) as count from table 
where age = 38
group by email
order by count
limit 100

email字段最多可达60个字符。

我不需要非常精确的结果,因此只要查询尽可能快地运行,我就可以得到近似结果。所以我愿意接受聪明的技巧,甚至可能是有趣的方法。

除了为email选择正确的数据类型并将ageemail编入索引之外,还有哪些其他技巧可以提供帮助?

例如,如果email大小平均大于32个字符,我会存储md5哈希。此外,我可以从@中删除.email因为我不在乎一些最终相互碰撞的电子邮件(abc@xyz.com和ab) @ cxyz.com将是abcxyzcom,它很好)。另外,我认为压缩email字段可能是一种选择。

4 个答案:

答案 0 :(得分:1)

看起来你的桌子设计得很差(以一种会损害性能而非帮助它的方式进行非规范化),并且应该重构为两个或更多的表格。虽然非规范化可能会使某些事情变得更容易,但它会使您需要每两分钟更新一次的查询非常昂贵 - 无论您如何操作。

如果你确实有充分的理由保持表格不规范化(而且这个原因不仅仅是"它会使插入更难"),你可能仍然需要一个仅包含唯一电子邮件地址的伪规范化表。在那里,您可以为每个电子邮件地址保留一个数字ID,并为您原来的表(您试图避免使用)保留外键,或者将电子邮件地址本身作为主键和您插入的列或者更新以反映该电子邮件地址的计数。无论何时插入原始表,还要将(带有ON DUPLICATE KEY UPDATE子句)插入到该电子邮件跟踪表中。

我敢打赌,将原始桌子标准化比追求这个更好,但这是一个选择。您的问题似乎并非如此,以至于电子邮件地址被非规范化,但该用户帐户信息被非规范化 - 您是否真的允许不同的用户拥有相同的电子邮件?如果您尝试报告特定年龄段的用户执行某项操作的次数,则应该使用比电子邮件地址更好的密钥 - 例如数字用户ID或者跟踪计数的表特定用户的行动。

答案 1 :(得分:0)

我同意丹。但是,您的问题的字面答案是保持您的查询和表格不变,并确保您的电子邮件上也有非聚集索引,该索引也具有年龄或包含年龄字段。

答案 2 :(得分:0)

如果您正在为从第三方系统加载的数据执行此操作,那么我建议您设计摘要表并运行查询并定期将结果缓存在摘要表中。例如,您可以每小时对此表运行查询,并根据需要提供存储电子邮件,计数和年龄的汇总表。我只是假设你想要存储其他年龄组的统计数据。我建议汇总表,因为您不需要准确的数据。这样,您就可以通过从摘要表加载统计信息来更快地在屏幕上呈现报告。

摘要表可以包含以下列:

- age_group
- email
- count 

或者可能只是

- email 
- count

我不确定您要提取哪些数据,但我希望看到age_group的电子邮件数量,而不是电子邮件。所以我会在摘要表中跟随两列:

- age_group
- count_of_email

所以我知道我系统中的年龄组用户是什么。

答案 3 :(得分:0)

以下是我向前迈进的方式。正如我所提到的,我不需要非常精确的结果,只要查询尽可能快地运行,我就可以得到近似结果。

所以我将电子邮件字段定义为bigint(8个字节,小尺寸,快速操作)并使用函数hex( substr( md5( email), 4, 8 ) )保存电子邮件我使用700K电子邮件地址列表进行了检查17对彼此相撞的电子邮件。因此,如果误差率为0.004%,我可以非常快速地运行聚合函数。

感谢您的见解。

PS。我尝试了不同pos变量的子串函数。从位置4开始看起来像是在md5哈希之后导致最少冲突的电子邮件。