每月日志表列表中的 MSSQL Efficient return

MSSQL Efficient return from list of Monthly Log Tables

我是 re-writing 一个连接到 MSSQL 并报告用户使用情况的报告(在 classic-asp 中)。

自从我们开始记录以来,我每个月都有多个“日志”表,每当用户登录系统时,他们都会添加一个类型为“成功登录”的日志。

在我的报告中,我正在尝试 return 基于用户 ID 的最新登录。

目前,我正在使用 ASP 创建数据库中所有日志表的循环,以“联合所有”,并在联合表中查询用户 ID 和“成功登录”的操作.这大约需要 30 分钟才能完成,因为日志已经变得如此之大。

如果我将搜索限制在最近 3 个月的表格中,这将减少到 5 分钟左右(数据库中有 14k+ 用户,报告提供的信息比他们上次登录的信息多得多,使用SQL执行计划管理器,我发现搜索这40多个日志表是瓶颈。

我一直在考虑在 SQL 中使用 If-Else 语句可能是 搜索多个表的一种方法,如果找不到一行,但我正在努力确定逻辑,而且一如既往,可能有一种更有效的方法来找到我什至没有考虑过的结果。

使用最近 3 个月

SELECT Name, (SELECT Top 1 LastLogin FROM (SELECT Top 1 Date As LastLogin FROM PARProjectLogs.dbo.Y2020M7 WHERE Y2020M7.UserID = Project_Users.UserID AND Type = 'Successful Login' ORDER BY Date Desc UNION ALL SELECT Top 1 Date As LastLogin FROM PARProjectLogs.dbo.Y2020M6 WHERE Y2020M6.UserID = Project_Users.UserID AND Type = 'Successful Login' ORDER BY Date Desc UNION ALL SELECT Top 1 Date As LastLogin FROM PARProjectLogs.dbo.Y2020M5 WHERE Y2020M5.UserID = Project_Users.UserID AND Type = 'Successful Login' ORDER BY Date Desc UNION ALL SELECT Top 1 Date As LastLogin FROM PARProjectLogs.dbo.Y2020M4 WHERE Y2020M4.UserID = Project_Users.UserID AND Type = 'Successful Login' ORDER BY Date Desc) As Tbl Order BY LastLogin Desc) As LastLogin FROM Project_Users ORDER BY Name

标题格式有Y2020M1、Y2020M2、Y2020M3、Y2020M4等多个数据库...

如果在较晚的日志中找到结果,如何避免搜索较早的日志?

为了提高性能,您可以去掉 select 语句中的子查询。 使用依赖于外部 select 的 where 子句在 select 中执行子查询意味着 SQL 服务器将逐行评估此行。

选项 1 将 GROUP BY 与 union 和 join 结合使用

SELECT Name
    , logins.LastLogin
FROM Project_Users pu
LEFT JOIN (
    SELECT UserId , MAX(LastLogin) LastLogin
        FROM (
            SELECT Y2020M7.UserID, DATE AS LastLogin
            FROM PARProjectLogs.dbo.Y2020M7
            WHERE Type = 'Successful Login'
            GROUP BY Y2020M7.UserID
            ORDER BY DATE DESC
            
            UNION ALL
            
            SELECT Y2020M6.UserID, DATE AS LastLogin
            FROM PARProjectLogs.dbo.Y2020M6
            WHERE Type = 'Successful Login'
            GROUP BY Y2020M6.UserID
            ORDER BY DATE DESC
            -- TODO other tables
            
            ) AS Tbl
        GROUP BY UserId
) logins on logins.UserId = pu.UserID
ORDER BY Name

选项 2 使用多个连接和 Max.


SELECT Name
    , (SELECT Max(v) 
   FROM (VALUES (loginsY2020M7.Date), (loginsY2020M6.loginsY2020M6),...) AS value(v)) as [LastLogin]
FROM Project_Users pu
LEFT JOIN (
    SELECT Y2020M7.UserID , MAX(DATE) Date
    FROM PARProjectLogs.dbo.Y2020M7
    WHERE  Type = 'Successful Login'
    GROUP BY Y2020M7.UserID
) loginsY2020M7 on loginsY2020M7.UserId = pu.UserId
LEFT JOIN (
    SELECT Y2020M6.UserID , MAX(DATE) Date
    FROM PARProjectLogs.dbo.Y2020M6
    WHERE  Type = 'Successful Login'
    GROUP BY Y2020M6.UserID
) loginsY2020M6 on loginsY2020M6.UserId = pu.UserId
-- TODO all other table in same way
ORDER BY Name 

通过使用 joingroup by SQL 服务器可以在集合上优化和执行,而不是像您的示例那样在行级别上执行。