每月日志表列表中的 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
通过使用 join
和 group by
SQL 服务器可以在集合上优化和执行,而不是像您的示例那样在行级别上执行。
我是 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
通过使用 join
和 group by
SQL 服务器可以在集合上优化和执行,而不是像您的示例那样在行级别上执行。