半径 SQL 查询 - 优化

Radius SQL query - optimize

我根本不是 SQL 专家,但我有一个 SQL 查询已在小型 FreeRadius 服务器上自动使用。现在我们想在更大的服务器上使用它,但我注意到查询需要很长时间,并且使用 CPU 100% 大约两分钟...

有人知道如何优化查询吗?目标是查找用户是否有多个活动登录,并获取最旧的信息。

我们也可以接受更多的结果,并在PHP中进行排序,以减少radius-database的负载。

这是我们今天使用的查询:

  SELECT username, acctstarttime, acctsessionid, nasipaddress, framedipaddress
        FROM radacct
        WHERE username IN (
            SELECT username
            FROM radacct
            WHERE acctstoptime IS NULL
            GROUP BY username
            HAVING COUNT(username) > 1
        )
        AND acctstoptime IS NULL
        GROUP BY username
        ORDER BY username, acctstarttime ASC

此致

要么删除子查询

SELECT username, acctstarttime, acctsessionid, nasipaddress, framedipaddress
        FROM radacct
        WHERE acctstoptime IS NULL
        GROUP BY username
        ORDER BY username, acctstarttime ASC
        HAVING COUNT(username) > 1

或从外部查询中删除 group by(如果您希望获得具有重复 username

的所有行

我认为我们可以对整个 radacct table:

进行一次传递
SELECT username, MIN(acctstarttime) AS min_start_time
FROM radacct
WHERE acctstoptime IS NULL
GROUP BY username
HAVING COUNT(*) >= 2
LIMIT 0, 30;

这 return 只有拥有两个或更多活动帐户的用户。它还会 return 每个用户的最新 acctstarttime 值。

查询响应是 100% 正确的,您应该可以一次完成。然而,2 分钟太疯狂了!我还怀疑单次通过这没有你想要的那么快。 我们有一个状态页面来显示在任何给定时刻出于支持原因在线的所有用户,这听起来与您正在尝试做的类似。

首先确保您有一个关于acctstoptime 的索引。 我还怀疑您在 MYSQL 配置中有一些错误的配置来处理这么大的 table。 我还强烈建议做一个存档数据库并将所有活动会话保存在一个小型数据库中,这将有助于大量更新和插入,而 free radius accounting 确实如此。

我们每天有超过 100,000 名活跃用户,中间更新时间为 300 秒,每年生成大约 3-40 亿行。我们的每个查询都不到 1 秒。我很乐意帮助您优化自由半径的东西。