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运行 的列。对其编制索引并在您的查询中使用它。
我有以下代码:
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运行 的列。对其编制索引并在您的查询中使用它。