SQL查询不存在大型记录集上的性能问题
我有下面列出的表格结构 表名:MachineLog(**979478条记录**) 表名称:员工详细信息(**798记录**) 表名:时间项(**73398记录**) 预期输出:SQL查询不存在大型记录集上的性能问题,sql,sql-server,sql-server-2012,Sql,Sql Server,Sql Server 2012,我有下面列出的表格结构 表名:MachineLog(**979478条记录**) 表名称:员工详细信息(**798记录**) 表名:时间项(**73398记录**) 预期输出: Companyid Employeeid InOutDate InOutTime -------------------------------------------------------- 12 3 2018-10-06 08:25
Companyid Employeeid InOutDate InOutTime
--------------------------------------------------------
12 3 2018-10-06 08:25
12 4 2018-10-06 09:26
12 4 2018-10-06 10:19
问题:
基本上,我想从MachineLog表中获取给定日期范围内的所有记录,但在时间条目表中标记为“M”的记录除外
但问题是,我编写的查询大约需要10-15分钟的时间来执行
我得到了适当的输出,但性能非常慢
如何提高以下查询的性能
查询:
SELECT [t0].[CompanyId],
[t0].[EmployeeId],
[t0].[InOutDate],
[t0].[InOutTime]
FROM [SCHEMA].[MachineLog] AS [t0]
JOIN [SCHEMA].[EmployeeDetail] AS [B] ON [t0].[EmployeeId] = [B].[Id]
WHERE (B.Category IN(15,17))
AND ([t0].[CompanyId] = 12)
AND ([t0].[InOutDate] >= '2018-09-30')
AND ([t0].[InOutDate] <= '2018-10-20')
AND (NOT (EXISTS
(SELECT NULL AS [EMPTY]
FROM [SCHEMA].[Entry] AS [t1]
WHERE ([t1].[EmployeeId] = [t0].[EmployeeId])
AND ([t1].[CompanyId] = 12)
AND (([t0].[InOutDate]) = [t1].[EntryDate])
AND ([t1].[EntryMethod] = 'M') )))
ORDER BY [t0].[EmployeeId],
[t0].[InOutDate]
选择[t0].[CompanyId],
[t0].[EmployeeId],
[t0].[InOutDate],
[t0].[InOutTime]
从[SCHEMA].[MachineLog]到[t0]
将[SCHEMA].[EmployeeDetail]作为[t0].[EmployeeId]=[B].[Id]上的[B]加入
其中(B.第(15,17)类)
和([t0].[CompanyId]=12)
和([t0].[InOutDate]>='2018-09-30')
并且([t0].[InOutDate]您可以通过临时表来解决这个问题
- 创建临时表t1,如下所示:
`insert into t1 (SELECT NULL AS [EMPTY]
FROM [SCHEMA].[Entry] AS [t1]
WHERE ([t1].[EmployeeId] = [t0].[EmployeeId])
AND ([t1].[CompanyId] = 11)
AND ([t0].[EmployeeId] = [t1].[EmployeeId])
AND (([t0].[InOutDate]) = [t1].[EntryDate])
AND ([t1].[EntryMethod] = 'M') `
- 主表左连接t1以排除数据:
`select * from m left join t1 on t1.id = m.id where m1.id is null`
这是未经测试的,但可能会节省时间。与where子句中的exists不同,您可能会反转逻辑并将其包含在join中
SELECT
[t0].[CompanyId],
[t0].[EmployeeId],
[t0].[InOutDate],
[t0].[InOutTime]
FROM
[SCHEMA].[MachineLog] AS [t0]
JOIN [SCHEMA].[EmployeeDetail] AS [B] ON [t0].[EmployeeId] = [B].[Id]
JOIN (SELECT [EmployeeId],[CompanyId],[EntryDate],[EntryMethod], COUNT(*) AS [DummyCount]
FROM [SCHEMA].[Entry]
GROUP BY [EmployeeId],[CompanyId],[EntryDate],[EntryMethod]) AS [t1]
ON ([t1].[EmployeeId] = [t0].[EmployeeId]
AND [t1].[CompanyId] = [t0].[CompanyId]
AND [t1].[EntryDate] = [t0].[InOutDate]
AND [t1].[EntryMethod] != 'M')
WHERE
(B.Category IN(15,17))
AND ([t0].[CompanyId] = 11)
AND ([t0].[InOutDate] >= '2018-09-30')
AND ([t0].[InOutDate] <= '2018-10-20')
ORDER BY
[t0].[EmployeeId],
[t0].[InOutDate]
选择
[t0].[CompanyId],
[t0].[EmployeeId],
[t0].[InOutDate],
[t0].[InOutTime]
从…起
[SCHEMA].[MachineLog]AS[t0]
将[SCHEMA].[EmployeeDetail]作为[t0].[EmployeeId]=[B].[Id]上的[B]加入
加入(选择[EmployeeId]、[CompanyId]、[EntryDate]、[EntryMethod]、计数(*)为[DummyCount]
来自[SCHEMA].[Entry]
按[EmployeeId]、[CompanyId]、[EntryDate]、[EntryMethod]分组为[t1]
在([t1].[EmployeeId]=[t0].[EmployeeId]
和[t1].[CompanyId]=[t0].[CompanyId]
和[t1].[EntryDate]=[t0].[InOutDate]
和[t1]。[EntryMethod]!='M')
哪里
(B.第(15,17)类)
和([t0].[CompanyId]=11)
和([t0].[InOutDate]>='2018-09-30')
并且([t0].[InOutDate]在没有执行计划的情况下,让我猜问题不在SQL语句中,而是在表的索引中
- 每个表是否都有一个主键和唯一的聚集索引
- 您是否正确定义和索引外键
- 应用了筛选器的最大表是MachineLog.InOutDate。该字段是否已编制索引
一旦这些设置正确,您的查询可能会运行
另一方面,我很好奇这个不存在(选择NULL作为[EMPTY]
我会写不存在(从…
中选择1
选择空值的任何原因?请提供查询计划和索引。如果您有独立数据-运气不好。更好的服务器、预先计算的表是用于报告式查询的标准解决方案(关键字:数据仓库)。使用CTRL-L观察查询计划并查找表扫描、感叹号和建议的索引。由于您没有发布任何索引,我猜您可能没有进行任何调查path@Nick.McDermaid我将检查查询执行计划,我还没有检查在条目、Employeeid、companyid、inoutdate、entrymet上放置索引hod-在[t0].[EmployeeId]=[t1].[EmployeeId]上还有一个重复的条件MachineLog表的InOutDate字段上的聚集索引肯定会有所帮助,同时也是TimeEntry表的EntryDate上的聚集索引,这是一个粗体语句请注意,entry表上的联接正在检查“EntryMethod”不等于“M”的位置,除非在entry
中有许多匹配的记录,在这种情况下,它将加倍count.sheet,你是对的。然后你可以对条目表进行一些虚拟聚合。让我编辑一下。对于性能问题,我建议至少在建议重写之前等待索引和查询计划定义。请注意,对其进行预聚合会做更多的工作,不太可能执行得更好。
`insert into t1 (SELECT NULL AS [EMPTY]
FROM [SCHEMA].[Entry] AS [t1]
WHERE ([t1].[EmployeeId] = [t0].[EmployeeId])
AND ([t1].[CompanyId] = 11)
AND ([t0].[EmployeeId] = [t1].[EmployeeId])
AND (([t0].[InOutDate]) = [t1].[EntryDate])
AND ([t1].[EntryMethod] = 'M') `
`select * from m left join t1 on t1.id = m.id where m1.id is null`
SELECT
[t0].[CompanyId],
[t0].[EmployeeId],
[t0].[InOutDate],
[t0].[InOutTime]
FROM
[SCHEMA].[MachineLog] AS [t0]
JOIN [SCHEMA].[EmployeeDetail] AS [B] ON [t0].[EmployeeId] = [B].[Id]
JOIN (SELECT [EmployeeId],[CompanyId],[EntryDate],[EntryMethod], COUNT(*) AS [DummyCount]
FROM [SCHEMA].[Entry]
GROUP BY [EmployeeId],[CompanyId],[EntryDate],[EntryMethod]) AS [t1]
ON ([t1].[EmployeeId] = [t0].[EmployeeId]
AND [t1].[CompanyId] = [t0].[CompanyId]
AND [t1].[EntryDate] = [t0].[InOutDate]
AND [t1].[EntryMethod] != 'M')
WHERE
(B.Category IN(15,17))
AND ([t0].[CompanyId] = 11)
AND ([t0].[InOutDate] >= '2018-09-30')
AND ([t0].[InOutDate] <= '2018-10-20')
ORDER BY
[t0].[EmployeeId],
[t0].[InOutDate]