gpt4 book ai didi

.net - 具有非常相似查询的 EF 性能非常不同

转载 作者:行者123 更新时间:2023-12-04 21:24:58 30 4
gpt4 key购买 nike

我们有两个 Entity Framework 查询,一个是 Include一种带有独立查询的。他们来了

        ConfigModelContainer model = new ConfigModelContainer();
var scope = model.Scopes.Include("Settings")
.Where(s => (s.Level == intLevel && s.Name == name))
.First();

ConfigModelContainer model = new ConfigModelContainer();
var scope = model.Scopes
.Where(s => (s.Level == intLevel && s.Name == name))
.First();
var settings = model.Settings.Where(s => s.Scope.Id == scope.Id).ToList();

另一个与第一个 (Query2) 具有相同性能的案例
        var scope1 = model.Scopes
.Where(s => (s.Level == intLevel && s.Name == name))
.First();
scope1.Settings.Load();

第一个运行 30 秒,第二个运行亚秒。这太奇怪了,我没有想法。

有谁知道为什么会发生这种情况?

编辑 :实际的 TSQL 查询运行速度非常快(亚秒级)

编辑 2 : 以下是查询:

第一的:
SELECT 
[Project2].[Level] AS [Level],
[Project2].[Id] AS [Id],
[Project2].[Name] AS [Name],
[Project2].[ParentScope_Id] AS [ParentScope_Id],
[Project2].[C1] AS [C1],
[Project2].[Id1] AS [Id1],
[Project2].[Type] AS [Type],
[Project2].[Value] AS [Value],
[Project2].[Scope_Id] AS [Scope_Id]
FROM ( SELECT
[Limit1].[Id] AS [Id],
[Limit1].[Name] AS [Name],
[Limit1].[Level] AS [Level],
[Limit1].[ParentScope_Id] AS [ParentScope_Id],
[Extent2].[Id] AS [Id1],
[Extent2].[Type] AS [Type],
[Extent2].[Value] AS [Value],
[Extent2].[Scope_Id] AS [Scope_Id],
CASE WHEN ([Extent2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
FROM (SELECT TOP (1)
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[Level] AS [Level],
[Extent1].[ParentScope_Id] AS [ParentScope_Id]
FROM [dbo].[Scopes] AS [Extent1]
WHERE ([Extent1].[Level] = @p__linq__0) AND ([Extent1].[Name] = @p__linq__1) ) AS [Limit1]
LEFT OUTER JOIN [dbo].[Settings] AS [Extent2] ON [Limit1].[Id] = [Extent2].[Scope_Id]
) AS [Project2]
ORDER BY [Project2].[Id] ASC, [Project2].[C1] ASC

第二:
SELECT 
[Limit1].[Level] AS [Level],
[Limit1].[Id] AS [Id],
[Limit1].[Name] AS [Name],
[Limit1].[ParentScope_Id] AS [ParentScope_Id]
FROM ( SELECT TOP (1)
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[Level] AS [Level],
[Extent1].[ParentScope_Id] AS [ParentScope_Id]
FROM [dbo].[Scopes] AS [Extent1]
WHERE ([Extent1].[Level] = @p__linq__0) AND ([Extent1].[Name] = @p__linq__1)
) AS [Limit1]

SELECT
1 AS [C1],
[Extent1].[Id] AS [Id],
[Extent1].[Type] AS [Type],
[Extent1].[Value] AS [Value],
[Extent1].[Scope_Id] AS [Scope_Id]
FROM [dbo].[Settings] AS [Extent1]
WHERE [Extent1].[Scope_Id] = @EntityKeyValue1

第三:
SELECT 
[Limit1].[Level] AS [Level],
[Limit1].[Id] AS [Id],
[Limit1].[Name] AS [Name],
[Limit1].[ParentScope_Id] AS [ParentScope_Id]
FROM ( SELECT TOP (1)
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[Level] AS [Level],
[Extent1].[ParentScope_Id] AS [ParentScope_Id]
FROM [dbo].[Scopes] AS [Extent1]
WHERE ([Extent1].[Level] = @p__linq__0) AND ([Extent1].[Name] = @p__linq__1)
) AS [Limit1]

SELECT
1 AS [C1],
[Extent1].[Id] AS [Id],
[Extent1].[Type] AS [Type],
[Extent1].[Value] AS [Value],
[Extent1].[Scope_Id] AS [Scope_Id]
FROM [dbo].[Settings] AS [Extent1]
WHERE [Extent1].[Scope_Id] = @p__linq__0

编辑 3 :

我无法在同一台机器上继续测试。这是在更快的机器上的结果。这是代码和结果:
    static void Main(string[] args)
{
int intLevel = 2;
string name = "fb226050-4f92-4fca-9442-f76565b33877";
Stopwatch sw = new Stopwatch();
using (CMEntities model = new CMEntities())
{
sw.Start();
for (int i = 0; i < 5; i++)
{

var scope1 = model.Scopes.Include("Settings")
.Where(s => (s.Level == intLevel && s.Name == name))
.First();

Console.WriteLine("Query:1, Iter:{0}, Time:{1}", i, sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
}
}
Console.WriteLine();
using (CMEntities model = new CMEntities())
{
sw.Start();
for (int i = 0; i < 5; i++)
{

var scope1 = model.Scopes
.Where(s => (s.Level == intLevel && s.Name == name))
.First();
scope1.Settings.Load();
Console.WriteLine("Query:2, Iter:{0}, Time:{1}", i, sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
}
}
Console.WriteLine();
using (CMEntities model = new CMEntities())
{
for (int i = 0; i < 5; i++)
{
var scope = model.Scopes
.Where(s => (s.Level == intLevel && s.Name == name))
.First();
var settings = model.Settings.Where(s => s.Scope.Id == scope.Id).ToList();
Console.WriteLine("Query:3, Iter:{0}, Time:{1}", i, sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
}
}
}
}

结果:
Query:1, Iter:0, Time:2477
Query:1, Iter:1, Time:1831
Query:1, Iter:2, Time:1933
Query:1, Iter:3, Time:1774
Query:1, Iter:4, Time:1949

Query:2, Iter:0, Time:2036
Query:2, Iter:1, Time:1870
Query:2, Iter:2, Time:1921
Query:2, Iter:3, Time:1751
Query:2, Iter:4, Time:1758

Query:3, Iter:0, Time:188
Query:3, Iter:1, Time:201
Query:3, Iter:2, Time:185
Query:3, Iter:3, Time:203
Query:3, Iter:4, Time:217

编辑 4 : 我用 NHibernate 重写了代码:
    static void Main(string[] args)
{

var cfg = new StoreConfiguration();
var sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005
.ConnectionString("Data Source=.;Initial Catalog=CM;Integrated Security=True;MultipleActiveResultSets=True")
)
.Mappings(m =>
m.AutoMappings.Add(
AutoMap.AssemblyOf<Entities.Scope>(cfg)
.Conventions
.Add(
Table.Is(x => x.EntityType.Name + "s"),
PrimaryKey.Name.Is(x => "Id"),
ForeignKey.EndsWith("_id")
)
)
)
.BuildSessionFactory();
Stopwatch sw = new Stopwatch();
for (int i = 0; i < 5; i++)
{
sw.Start();
var session = sessionFactory.OpenSession();
int intLevel = 2;
string name = "fb226050-4f92-4fca-9442-f76565b33877";
var scope = session.CreateCriteria<Entities.Scope>()
.SetFetchMode("Settings", FetchMode.Eager)
.Add(Restrictions.Eq("Name", name))
.Add(Restrictions.Eq("Level", intLevel))
.UniqueResult<Entities.Scope>();
Console.WriteLine("Query:0, Iter:{0}, Time:{1}", i, sw.ElapsedMilliseconds);
sw.Reset();
}
}

结果是:
Query:0, Iter:0, Time:446
Query:0, Iter:1, Time:223
Query:0, Iter:2, Time:303
Query:0, Iter:3, Time:275
Query:0, Iter:4, Time:284

因此 NHibernate 形成正确集合的速度比 EF 快 10 倍。这真的很可悲。

这是 NHibernate 生成的查询:
SELECT this_.id            AS id0_1_, 
this_.name AS name0_1_,
this_.LEVEL AS level0_1_,
settings2_.scope_id AS scope4_3_,
settings2_.id AS id3_,
settings2_.id AS id1_0_,
settings2_.TYPE AS type1_0_,
settings2_.VALUE AS value1_0_,
settings2_.scope_id AS scope4_1_0_
FROM scopes this_
LEFT OUTER JOIN settings settings2_
ON this_.id = settings2_.scope_id
WHERE this_.name = @p0
AND this_.LEVEL = @p1

最佳答案

有几件事要检查...

  • 实体模型中 Scopes 和 Settings 之间的关系是如何定义的?是否使用了正确的外键?多重性如何(一对多等)?
  • 如果您将第一个查询更改为:
  • ,您的执行时间是否会有所改善?

    .
    ConfigModelContainer model = new ConfigModelContainer();
    var scope = model.Scopes.Include("Settings")
    .First<Scope>(s => s.Level == intLevel && s.Name == name);

    我不确定 Linq 是否会优化与您不同的查询,但也许看看它是否会这样做。

    至于升级到 EF 4.0,我不知道如果您的项目是在 .NET 3.5 中,这有多可行。尽管如此,当我们的项目使用 .NET 3.5/EF 1 时,我从未遇到过这个问题。

    关于.net - 具有非常相似查询的 EF 性能非常不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5205281/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com