Linq to Entities,当我尝试使用 group .. by 时操作超时

Linq to Entities, Operation timeout when I try to use group .. by

我有以下代码:

        var statList = (from i in _dbContext.Screenshots
                       where EntityFunctions.TruncateTime(i.dateTimeServer.Value) >= startDate && EntityFunctions.TruncateTime(i.dateTimeServer.Value) <= endDate
                       group i by EntityFunctions.TruncateTime(i.dateTimeServer.Value)
                           into g
                           select new ScreenshotStatistic()
                           {
                               Date = g.Key.Value,
                               AllScreenshots = g.Count(),
                               ScreenshotsNoSilent = g.Where(p => p.version.IndexOf("silent") == 0).Count(),
                               ScreenshotsNoSilentWithViews = g.Where(p => p.version.IndexOf("silent") == 0 && p.viewsPage + p.viewsOriginal > 0).Count(),
                               ScreenshotsOnlySilent = g.Where(p => p.version.IndexOf("silent") >= 0).Count(),
                               ScreenshotsOnlySilentWithViews = g.Where(p => p.version.IndexOf("silent") >= 0 && p.viewsPage + p.viewsOriginal > 0).Count(),
                               ScreenshotsOnlyUploadViaSite = g.Where(p => p.version.IndexOf("UPLOAD_VIA_SITE") >= 0).Count(),
                               ScreenshotsOnlyUploadViaSiteWithViews = g.Where(p => p.version.IndexOf("UPLOAD_VIA_SITE") >= 0 && p.viewsPage + p.viewsOriginal > 0).Count()
                           }).ToList();

它对我的本地数据库非常有效,但是当我尝试连接到 SQL Azure 时,我得到 "Operation timeout"。据我了解,我的请求未优化。我怎样才能更好地完成请求?

table 具有以下结构:

CREATE TABLE [dbo].[Screenshots](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [dateTimeClient] [datetime] NOT NULL,
    [name] [nvarchar](500) NOT NULL,
    [username] [varchar](50) NULL,
    [filename] [nvarchar](50) NULL,
    [description] [nvarchar](500) NULL,
    [version] [varchar](50) NULL,
    [lang] [varchar](50) NULL,
    [dateTimeServer] [datetime] NULL CONSTRAINT [DF_Screenshots_dateTimeServer]  DEFAULT (getdate()),
    [isPublic] [bit] NOT NULL CONSTRAINT [DF_Screenshots_isPublic]  DEFAULT ((0)),
    [viewsPage] [int] NOT NULL CONSTRAINT [DF_Screenshots_viewsPage_1]  DEFAULT ((0)),
    [viewsThumb] [int] NOT NULL CONSTRAINT [DF_Screenshots_viewsThumb_1]  DEFAULT ((0)),
    [viewsOriginal] [int] NOT NULL CONSTRAINT [DF_Screenshots_viewsOriginal_1]  DEFAULT ((0)),
    [statusID] [int] NOT NULL,
 CONSTRAINT [PK_Screenshots] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[Screenshots]  WITH CHECK ADD  CONSTRAINT [FK_Screenshots_ScreenshotStatuses] FOREIGN KEY([statusID])
REFERENCES [dbo].[ScreenshotStatuses] ([ID])
ON UPDATE CASCADE
ON DELETE CASCADE
GO

ALTER TABLE [dbo].[Screenshots] CHECK CONSTRAINT [FK_Screenshots_ScreenshotStatuses]
GO

EntityFunctions.TruncateTime 正在翻译成:

convert (datetime2, convert(varchar(255), [dateTimeServer], 102) ,  102)

这导致您的查询 non-sargable,导致性能下降和超时。我建议进行以下更改


首先,我不明白您为什么需要在 where 子句中添加时间 运行。我建议您进行此更改:

where i.dateTimeServer.Value >= startDate && i.dateTimeServer.Value <= endDate

这将避免数据库必须 运行 每个记录上的函数。


如果查询仍然超时,我会将 group by 更改为:

group i by new { 
   i.dateTimeServer.Value.Year, 
   i.dateTimeServer.Value.Month, 
   i.dateTimeServer.Value.Day 
}

这在功能上是一样的,但我相信它会产生更友好的翻译:

DATEPART (year, dateTimeServer), DATEPART (month, dateTimeServer) etc..

添加索引到dateTimeServer


如果所有其他方法都失败了,您将需要在 table 中添加一个包含时间部分 t运行 的列。对其编制索引并在您的查询中使用它。