【问题标题】:MySql SUBSTRING_INDEX how not use sequence scanMySql SUBSTRING_INDEX 如何不使用序列扫描
【发布时间】:2016-04-25 17:00:32
【问题描述】:

我有表结构 MySql v 5.7.11:

CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`gender` tinyint(2) NOT NULL,
`email` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
);

而且这张表有超过1亿条记录 我需要从电子邮件字段中获取邮件域并按每个域进行计数,例如:google.com、yahoo.com 等。

我使用查询:

SELECT
  SUBSTRING_INDEX(`users`.`email`, '@', -1) col1,
  count(1)
FROM `users`
GROUP BY 1

但是这个查询需要2分钟多的时间。我无法更改此表的结构。如何不使用序列扫描,以及如何加速此查询?

【问题讨论】:

  • 你使用什么 MySQL 版本?
  • 导致性能问题的不是扫描,而是group by上的文件排序。

标签: mysql sql


【解决方案1】:

很遗憾,如果不更改数据结构,您将无法加快查询速度。最直接的解决方案是添加一个generated column,它可以即时计算域并存储它,您的查询将在该字段上运行。

如果您绝对不能在此表中添加字段,您仍然可以向数据库中添加另一个表,该表将保存用户表的 id 和域名。您将更新后和插入后触发器添加到用户表,用于计算每个新用户或更新用户记录的电子邮件域名。您最初还必须填写新表。您的查询将在新表上运行得更快。

【讨论】:

  • 值得一提:生成的列可以被索引(虚拟列仅来自 MySQL 7.7)。
【解决方案2】:

似乎没有一种直接的方法可以在不修改表的情况下加速此查询,因为它不能使用索引。

但是,请考虑您的用例。即功能是否足够重要,您的应用程序可以单独跟踪这些统计信息?例如,如果您的 users_email_stats 表包括列 domaintotal,那么您可以

  • 将上述查询中的数据预加载到其中
  • 每次触碰用户电子邮件时更新总数(使用数据库触发器或从您的应用程序)

此表的优势在于:

  • 与主要用户表相比相对紧凑
  • 完全一次性,因为可以从users 轻松重建数据
  • 准确包含您需要的数据,查询速度非常快

显而易见的成本是更新计数器的额外维护。

【讨论】:

    猜你喜欢
    • 2021-03-19
    • 2013-03-07
    • 2018-05-05
    • 1970-01-01
    • 2014-07-29
    • 1970-01-01
    • 2015-11-23
    • 2021-09-04
    • 2015-04-02
    相关资源
    最近更新 更多