我正在从Log表中读取记录。该表目前有260,000条记录,共8列。这是通过EF6的代码。
using (var ctx = new DbEntities())
{
ctx.Configuration.ProxyCreationEnabled = false;
ctx.Configuration.AutoDetectChangesEnabled = false;
ctx.Configuration.LazyLoadingEnabled = false;
Stopwatch sw = Stopwatch.StartNew();
var k = ctx.Logs.Where(l => l.ApplicationId == id && l.Level <= 3 && (l.Dat == 20160514 ||l.Dat == 20160513 ) ).ToList();
sw.Stop();
}
以上需要7-8秒才能返回2213行。在SSMS上运行等效的故事不到一秒钟。
我也试过将查询作为
运行ctx.Logs.SqlQuery("SELECT * FROM Log WITH(NOLOCK) WHERE ApplicationId = 4 and Level <= 3 and (Dat = 20160513 or Dat = 20160514)").AsNoTracking().ToList();
这也需要约7秒
我有2个非群集密钥,一个是ApplicationId DESC,另一个是ApplicationId DESC,Dat DESC,Level ASC。
活动监视器从不显示数据库上的负载。
对于此大小的查询,这似乎很长一段时间。或者我的期望是否有偏差?
任何人都可以看到我做错的事吗?
注意* Sql位于具有4个内核和8GB内存的Azure VM上,其内存为3GB
注意*我现在知道我不应该调用我的列级别
修改
以下内容来自EF6 Log
SELECT
[Extent1].[LogId] AS [LogId],
[Extent1].[ApplicationId] AS [ApplicationId],
[Extent1].[Type] AS [Type],
[Extent1].[Source] AS [Source],
[Extent1].[Message] AS [Message],
[Extent1].[LogTime] AS [LogTime],
[Extent1].[Level] AS [Level],
[Extent1].[Dat] AS [Dat]
FROM [dbo].[Log] AS [Extent1]
WHERE ([Extent1].[ApplicationId] = @p__linq__0) AND ([Extent1].[Level] <= 3) AND ([Extent1].[Dat] IN (20160514,20160513))
-- p__linq__0: '2648' (Type = Int32, IsNullable = false)
-- Executing at 5/14/2016 8:38:38 PM -04:00
-- Completed in 101 ms with result: SqlDataReader
看起来查询速度非常快。那么为什么ToList()这么慢?
答案 0 :(得分:3)
EF必须将SQL的结果映射到对象中,这可能涉及反射和动态加载映射器以将SQL结果转换为logs
列表。如果您计算单个结果,请尝试多次在同一个上下文中执行相同的操作。您会发现每个结果执行时间会减少。这是因为映射器已经加载,不需要检索。
我不是EF的专家,我只是尝试了同样的问题,发现几秒延迟只是第一次针对上下文执行的问题。
答案 1 :(得分:0)
答案 2 :(得分:-1)
经过一些试验和错误,我发现我可以减少至少一半的时间。
首先进行Count()调用,然后我可以将请求分成多个部分,并以较小的增量逐页请求。
所以同样的2213个项目现在需要3-4秒才能并行进行两次调用,每个只有1000个。 10,000件物品过去需要60秒,这种方法约为18秒。
ds = pd.Series(['a','ab','b','a'])
ds
0 a
1 ab
2 b
3 a
dtype: object
ds.apply(lambda x: 1 if 'b' in x else 0)
0 0
1 1
2 1
3 0
dtype: int64
小于1000似乎没有给出更好的结果。