我在 c# 中有一个 linq to sql 查询可以工作 - 但在将数据摘要输出到网页的 ASP.NET 应用程序中使用时会导致性能非常差。此查询尝试对来自单个 log4net 表的日志进行分组。没有连接。
.GroupBy(l => new
{
Level = l.Level,
Period = ((DateTime.Now - l.Created).TotalMinutes <= 60)
? "Within last hour"
: (((DateTime.Now - l.Created).TotalMinutes > 60) &&
((DateTime.Now - l.Created).TotalMinutes <= 360)
)
? "Within last 6 hours"
: (((DateTime.Now - l.Created).TotalMinutes > 360) &&
((DateTime.Now - l.Created).TotalMinutes <= 1440)
)
? "Within last 24 hours"
: (((DateTime.Now - l.Created).TotalMinutes >
1440) &&
((DateTime.Now - l.Created).TotalMinutes <=
10080)
)
? "Within last week"
: (((DateTime.Now - l.Created).
TotalMinutes > 10080) &&
((DateTime.Now - l.Created).
TotalMinutes <= 302400)
)
? "Within last month"
: (((DateTime.Now - l.Created).
TotalMinutes > 302400) &&
((DateTime.Now - l.Created).
TotalMinutes <= 907200)
)
? "Within last quarter"
: (((DateTime.Now -
l.Created).
TotalMinutes >
907200) &&
((DateTime.Now -
l.Created).
TotalMinutes <=
3628800)
)
? "Current year"
: ((DateTime.Now -
l.Created).
TotalMinutes >
3628800)
? "Before current year"
: String.Empty,
PeriodType = ((DateTime.Now - l.Created).TotalMinutes <= 60)
? 1
: (((DateTime.Now - l.Created).TotalMinutes > 60) &&
((DateTime.Now - l.Created).TotalMinutes <= 360)
)
? 2
: (((DateTime.Now - l.Created).TotalMinutes >
360) &&
((DateTime.Now - l.Created).TotalMinutes <=
1440)
)
? 3
: (((DateTime.Now - l.Created).
TotalMinutes > 1440) &&
((DateTime.Now - l.Created).
TotalMinutes <= 10080)
)
? 4
: (((DateTime.Now - l.Created).
TotalMinutes > 10080) &&
((DateTime.Now - l.Created).
TotalMinutes <= 302400)
)
? 5
: (((DateTime.Now - l.Created)
.TotalMinutes >
302400) &&
((DateTime.Now - l.Created)
.TotalMinutes <=
907200)
)
? 6
: (((DateTime.Now -
l.Created).
TotalMinutes >
907200) &&
((DateTime.Now -
l.Created).
TotalMinutes <=
3628800)
)
? 7
: ((DateTime.Now -
l.Created).
TotalMinutes >
3628800)
? 8
: 0
}
).ToList();
当我运行 SQL 探查器时,我发现实际正在运行的查询是这样的:
SELECT
[Extent1].[LogID] AS [LogID],
[Extent1].[Created] AS [Created],
[Extent1].[RoleInstance] AS [RoleInstance],
[Extent1].[DeploymentId] AS [DeploymentId],
[Extent1].[Machine] AS [Machine],
[Extent1].[Thread] AS [Thread],
[Extent1].[Level] AS [Level],
[Extent1].[Logger] AS [Logger],
[Extent1].[Message] AS [Message],
[Extent1].[Exception] AS [Exception]
FROM [dbo].[Logs] AS [Extent1]
本质上,看起来所有的分组等都是在客户端完成的。由于 Web 服务器和数据库服务器之间的链接很慢 - 这导致网页实际显示结果之前需要很长时间。此外,日志数据库越大,响应越慢。
奇怪的是——当我在 LinqPad 中运行类似的查询时——我得到了一个完全不同的计划——像这样(略有不同的查询):
exec sp_executesql N'SELECT COUNT(*) AS [Count], [t1].[Level], [t1].[value] AS [Period], [t1].[value2] AS [PeriodType]
FROM (
SELECT [t0].[Level],
(CASE
WHEN ((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p0))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p0), [t0].[Created]), @p0)) * 10000))) / 600000000) <= @p1 THEN CONVERT(NVarChar(20),@p2)
WHEN (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p3))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p3), [t0].[Created]), @p3)) * 10000))) / 600000000) > @p4) AND (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p5))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p5), [t0].[Created]), @p5)) * 10000))) / 600000000) <= @p6) THEN CONVERT(NVarChar(20),@p7)
WHEN (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p8))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p8), [t0].[Created]), @p8)) * 10000))) / 600000000) > @p9) AND (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p10))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p10), [t0].[Created]), @p10)) * 10000))) / 600000000) <= @p11) THEN @p12
WHEN (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p13))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p13), [t0].[Created]), @p13)) * 10000))) / 600000000) > @p14) AND (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p15))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p15), [t0].[Created]), @p15)) * 10000))) / 600000000) <= @p16) THEN CONVERT(NVarChar(20),@p17)
WHEN (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p18))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p18), [t0].[Created]), @p18)) * 10000))) / 600000000) > @p19) AND (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p20))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p20), [t0].[Created]), @p20)) * 10000))) / 600000000) <= @p21) THEN CONVERT(NVarChar(20),@p22)
WHEN (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p23))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p23), [t0].[Created]), @p23)) * 10000))) / 600000000) > @p24) AND (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p25))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p25), [t0].[Created]), @p25)) * 10000))) / 600000000) <= @p26) THEN CONVERT(NVarChar(20),@p27)
WHEN (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p28))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p28), [t0].[Created]), @p28)) * 10000))) / 600000000) > @p29) AND (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p30))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p30), [t0].[Created]), @p30)) * 10000))) / 600000000) <= @p31) THEN CONVERT(NVarChar(20),@p32)
WHEN ((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p33))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p33), [t0].[Created]), @p33)) * 10000))) / 600000000) > @p34 THEN CONVERT(NVarChar(20),@p35)
ELSE CONVERT(NVarChar(20),@p36)
END) AS [value],
(CASE
WHEN ((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p37))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p37), [t0].[Created]), @p37)) * 10000))) / 600000000) <= @p38 THEN @p39
WHEN (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p40))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p40), [t0].[Created]), @p40)) * 10000))) / 600000000) > @p41) AND (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p42))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p42), [t0].[Created]), @p42)) * 10000))) / 600000000) <= @p43) THEN @p44
WHEN (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p45))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p45), [t0].[Created]), @p45)) * 10000))) / 600000000) > @p46) AND (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p47))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p47), [t0].[Created]), @p47)) * 10000))) / 600000000) <= @p48) THEN @p49
WHEN (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p50))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p50), [t0].[Created]), @p50)) * 10000))) / 600000000) > @p51) AND (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p52))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p52), [t0].[Created]), @p52)) * 10000))) / 600000000) <= @p53) THEN @p54
WHEN (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p55))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p55), [t0].[Created]), @p55)) * 10000))) / 600000000) > @p56) AND (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p57))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p57), [t0].[Created]), @p57)) * 10000))) / 600000000) <= @p58) THEN @p59
WHEN (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p60))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p60), [t0].[Created]), @p60)) * 10000))) / 600000000) > @p61) AND (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p62))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p62), [t0].[Created]), @p62)) * 10000))) / 600000000) <= @p63) THEN @p64
WHEN (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p65))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p65), [t0].[Created]), @p65)) * 10000))) / 600000000) > @p66) AND (((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p67))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p67), [t0].[Created]), @p67)) * 10000))) / 600000000) <= @p68) THEN @p69
WHEN ((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t0].[Created], @p70))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t0].[Created], @p70), [t0].[Created]), @p70)) * 10000))) / 600000000) > @p71 THEN @p72
ELSE @p73
END) AS [value2]
FROM [Logs] AS [t0]
) AS [t1]
GROUP BY [t1].[Level], [t1].[value], [t1].[value2]',N'@p0 datetime,@p1 float,@p2 nvarchar(4000),@p3 datetime,@p4 float,@p5 datetime,@p6 float,@p7 nvarchar(4000),@p8 datetime,@p9 float,@p10 datetime,@p11 float,@p12 nvarchar(4000),@p13 datetime,@p14 float,@p15 datetime,@p16 float,@p17 nvarchar(4000),@p18 datetime,@p19 float,@p20 datetime,@p21 float,@p22 nvarchar(4000),@p23 datetime,@p24 float,@p25 datetime,@p26 float,@p27 nvarchar(4000),@p28 datetime,@p29 float,@p30 datetime,@p31 float,@p32
nvarchar(4000),@p33 datetime,@p34 float,@p35 nvarchar(4000),@p36 nvarchar(4000),@p37 datetime,@p38 float,@p39 int,@p40 datetime,@p41 float,@p42 datetime,@p43 float,@p44 int,@p45 datetime,@p46 float,@p47 datetime,@p48 float,@p49 int,@p50 datetime,@p51 float,@p52 datetime,@p53 float,@p54 int,@p55 datetime,@p56 float,@p57 datetime,@p58 float,@p59 int,@p60 datetime,@p61 float,@p62 datetime,@p63 float,@p64 int,@p65 datetime,@p66 float,@p67 datetime,@p68 float,@p69 int,@p70 datetime,@p71 float,@p72 int,@p73 int',@p0='2012-07-11 23:46:56.457',@p1=60,@p2=N'Within last hour',@p3='2012-07-11 23:46:56.457',@p4=60,@p5='2012-07-11 23:46:56.457',@p6=360,@p7=N'Within last 6 hours',@p8='2012-07-11 23:46:56.457',@p9=360,@p10='2012-07-11 23:46:56.457',@p11=1440,@p12=N'Within last 24 hours',@p13='2012-07-11 23:46:56.457',@p14=1440,@p15='2012-07-11 23:46:56.457',@p16=10080,@p17=N'Within last week',@p18='2012-07-11 23:46:56.457',@p19=10080,@p20='2012-07-11 23:46:56.457',@p21=302400,@p22=N'Within last month',@p23='2012-07-11 23:46:56.457',@p24=302400,@p25='2012-07-11 23:46:56.457',@p26=907200,@p27=N'Within last quarter',@p28='2012-07-11 23:46:56.457',@p29=907200,@p30='2012-07-11 23:46:56.457',@p31=3628800,@p32=N'Current year',@p33='2012-07-11 23:46:56.457',@p34=3628800,@p35=N'Before current year',@p36=N'',@p37='2012-07-11 23:46:56.460',@p38=60,@p39=1,@p40='2012-07-11 23:46:56.460',@p41=60,@p42='2012-07-11 23:46:56.460',@p43=360,@p44=2,@p45='2012-07-11 23:46:56.460',@p46=360,@p47='2012-07-11 23:46:56.460',@p48=1440,@p49=3,@p50='2012-07-11 23:46:56.460',@p51=1440,@p52='2012-07-11 23:46:56.460',@p53=10080,@p54=4,@p55='2012-07-11 23:46:56.460',@p56=10080,@p57='2012-07-11 23:46:56.460',@p58=302400,@p59=5,@p60='2012-07-11 23:46:56.460',@p61=302400,@p62='2012-07-11 23:46:56.460',@p63=907200,@p64=6,@p65='2012-07-11 23:46:56.460',@p66=907200,@p67='2012-07-11 23:46:56.460',@p68=3628800,@p69=7,@p70='2012-07-11 23:46:56.460',@p71=3628800,@p72=8,@p73=0
现在,如果这是我在 c# 中编写的查询的结果,那么输出到网页所需的时间会大大减少。
在调试 c# 代码时,我尝试了几个选项 - 围绕在 linq 查询的各个点添加 .ToList() 语句。我什至尝试在 EF4 设计器中更改 LazyLoadingEnabled。当我查看 SQL 探查器时,似乎没有什么可以使用正确的计划。我也尝试过 DataLoadOptions - 但它们似乎也没有任何不同,因为看起来这些选项在使用表连接时会更有用。
我究竟做错了什么?如何让 group by 和任何其他聚合发生在数据库服务器上,以便将更少的记录传输到网络服务器?这是由于 Linq 中的延迟加载造成的吗?我该如何纠正?谢谢