SQL查询不存在大型记录集上的性能问题

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

我有下面列出的表格结构

表名:MachineLog(**979478条记录**)

表名称:员工详细信息(**798记录**)

表名:时间项(**73398记录**)

预期输出:

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]