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;
id
表的users
字段与userid
表的account
字段相同。这就是为什么 account
表与该列上的 users
保持连接。另外,number
表的account
列与login
表的deals
列相同,这就是为什么该列上有另一个左连接。
执行上述查询需要 1 分钟。即使是 1 个月的数据。太费时间了。
请帮忙。可以做些什么来优化这个查询吗?下面是解释
这是我优化此查询的方法。它基于一些猜测,因为您尚未提供表和索引定义。
我们将为您最大的桌子提供服务。
您最大的表是
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 索引,因此它的前三列允许查询规划器随机访问它到第一个有用的行,然后按顺序范围扫描索引到最后一个有用的行。这样就节省了全表扫描。查询规划器不会检查日期超出您想要的范围的行。
索引的最后两列包含其余查询所需的数据。这意味着规划器不需要执行其他操作来获取数据,并且可以直接从索引中获取数据。