Mysql 递归 CTE 和两个左连接使查询运行速度极其缓慢。如何优化查询?

问题描述 投票:0回答:1
SELECT
    t.id,
    t.name,
    t.email,
    t.parentId,
    SUM(d.volume) AS total_volume
FROM (
    WITH RECURSIVE users_path (id, parentId, name, email, path) AS (
        SELECT id, parentib AS parentId, name, email, name AS path
        FROM users
        WHERE parentib = 72
        UNION ALL
        SELECT c.id, c.parentib, c.name, c.email, CONCAT(cp.path, ' > ', c.name)
        FROM users_path AS cp
        JOIN users AS c ON cp.id = c.parentib
    )
    SELECT *
    FROM users_path
    ORDER BY path
) AS t
LEFT JOIN account a ON t.id = a.userid AND a.isdemo = 0 AND a.active = 1 AND a.disabled = 0
LEFT JOIN live5.deals d ON a.number = d.login AND (d.action = 0 OR d.action = 1) AND d.entry = 1 AND d.time >= "2023-10-01" AND d.time <= "2023-10-24"
GROUP BY t.id, t.name, t.parentId
ORDER BY t.path;
  • Users 表有 31K 条记录
  • 账户有36K条记录
  • 交易有5854K记录

id
表的
users
字段与
userid
表的
account
字段相同。这就是为什么
account
表与该列上的
users
保持连接。另外,
number
表的
account
列与
login
表的
deals
列相同,这就是为什么该列上有另一个左连接。

执行上述查询需要 1 分钟。即使是 1 个月的数据。太费时间了。

请帮忙。可以做些什么来优化这个查询吗?下面是解释

mysql database query-optimization
1个回答
0
投票

这是我优化此查询的方法。它基于一些猜测,因为您尚未提供表和索引定义。

我们将为您最大的桌子提供服务。

您最大的表是

deals
,您的解释输出显示它正在进行(慢)全表扫描来满足您的查询。因此,覆盖索引会有所帮助。

从该表中,您的 ON 子句对

entry
action
time
进行相等匹配。您使用
login
连接回您的
account
表,然后您的 SELECT 子句求和
volume

因此,这个 BTREE 索引可能会加速您的查询。

CREATE INDEX entry_action_time_login_volume ON live5.deals
    (entry, action, time, login, volume)

它是一个 BTREE 索引,因此它的前三列允许查询规划器随机访问它到第一个有用的行,然后按顺序范围扫描索引到最后一个有用的行。这样就节省了全表扫描。查询规划器不会检查日期超出您想要的范围的行。

索引的最后两列包含其余查询所需的数据。这意味着规划器不需要执行其他操作来获取数据,并且可以直接从索引中获取数据。

© www.soinside.com 2019 - 2024. All rights reserved.