【问题标题】:How to speed up sql with GROUP BY and WHERE?如何使用 GROUP BY 和 WHERE 加速 sql?
【发布时间】:2020-07-10 18:33:30
【问题描述】:

我知道使用索引可以优化带有GROUP BYWHERE 子句的SQL。但是如何使用GROUP BYWHERE 优化SQL?请看我的情况。

我有一个表来存储流量数据并用它来绘制网络流量拓扑。下面是表结构:

DROP TABLE IF EXISTS `data`;

CREATE TABLE `data` 
(
    `sip` varbinary(16) DEFAULT NULL,
    `dip` varbinary(16) DEFAULT NULL,
    `app` char(96) DEFAULT NULL,
    `up` bigint(20) DEFAULT NULL,
    `down` bigint(20) DEFAULT NULL,
    `dtime` datetime DEFAULT CURRENT_TIMESTAMP,
    KEY `dtime` (`dtime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

并在列dtime 上创建索引。

简化的SQL是

SELECT
    INET6_NTOA(sip),
    INET6_NTOA(dip),
    app,
    sum(up) AS up,
    sum(down) AS down
FROM
    `data`
WHERE
    `data`.dtime > FROM_UNIXTIME(1583031879)
AND `data`.dtime < FROM_UNIXTIME(1585537477)
GROUP BY
    sip,
    dip,
    app

该表可以存储大约10,000,000条一个月的记录,我们的要求是绘制一个粒度为Last 30 days, Last 24 hours, Last 1 hours的网络流量拓扑。

显然索引dtime 有助于查询最近1 小时或最近24 小时的数据。但是查询过去 30 天时,是全表扫描。

极端情况下,查询24小时耗时5s,可以接受,查询30天耗时60s+,难以接受。

为 sip,dip,app 创建索引?似乎没有帮助,因为我首先必须按 dtime 过滤数据。我搜索了各种索引解决方案,可能不适合我。

有什么想法可以加快我的 SQL 速度吗?或者有什么改进餐桌设计的想法吗?非常感谢。

【问题讨论】:

    标签: mysql optimization indexing group-by


    【解决方案1】:

    简单地说,WHERE 中的“范围”会阻止索引对GROUP BYORDER BY 有用。您可以添加INDEX(sip, dip, app) 给优化器一个选择。

    每张桌子都需要一个PRIMARY KEY。也许它可能是PRIMARY KEY(sip, dip, app)?还是只是(sip, dip)?请注意,将其设为 PK 会比简单的 INDEX 更好。

    但这些报告的真正性能提升将是构建和维护一个粒度为 1 小时的“汇总表”。一小时可以让您有效地获取小时、日、月等信息。请参阅http://mysql.rjweb.org/doc.php/summarytables 而且,由于汇总表会小得多,因此何时需要进行表扫描并不重要。

    VARBINARY(16) 是某种形式的哈希吗?还是一对IP地址?如果它们是固定长度的,请考虑CHAR(16)

    updown 可以有多大?也许您不需要 8 字节的BIGINT? (节省空间有助于提高性能。

    MySQL 每个SELECT 只使用一个索引。优化器查看每个索引(包括PRIMARY KEY)来估计哪个一个是最好的。在您的情况下,它会权衡使用INDEX(dtime) 进行过滤与使用INDEX(sip,dip,app) 以避免排序之间的选择。

    如果WHERE 子句过滤到很少的行; dtime 索引会更好,优化器可能会使用它。反之亦然。

    【讨论】:

    • 感谢您的评论。 1. 你的意思是INDEX(sip,dip,app) 在使用INDEX(dtime) 时将不起作用? 2. 我应该比较优化器效果以选择INDEX(sip,dip,app)INDEX(dtime) 之一 3. 不幸的是,(sip,dip,app)INDEX(sip,dip) 都不是主键。此表记录了从源 IP 到目标 IP 的应用流量。可能的主键是(sip,dip,app,dtime)。在这种情况下,PK 索引似乎对wheregroupby 没有影响。 4.VARBINARY(16)用于存储IPV6地址。 5. 关于 8 字节 BIGINT 提示,再次感谢。
    • @Does - 我添加了一些。
    【解决方案2】:

    您可以尝试使用索引(sip、dip、app)(3 列索引)吗?我认为这可能会有所帮助。

    【讨论】:

    • 仅在 (sip,dip,app) 上创建索引时,它的成本高达 4000s+。在 (dtime) 和 (sip,dip,app) 上创建索引时,花费 60s+。你能解释一下为什么 index(sip,dip,app) 有用吗?
    • 您应该绝对使用 2 个索引来表示 dtime 和 (sip, dip, app)。复合索引(sip、dip、app)与 MySQL GroupBy 处理逻辑有关。 [dev.mysql.com/doc/refman/8.0/en/group-by-optimization.html]
    • 如果优化器选择使用(sip,dip,app),那么它可以避免排序。如果是PRIMARY KEY,其他细节有助于加快速度。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多