首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >视图会降低EF查询性能吗?

问视图会降低EF查询性能吗?
EN

Stack Overflow用户
提问于 2014-01-24 07:46:31
回答 2查看 2.5K关注 0票数 2

我正在寻找一些技巧来改进我的实体框架查询性能,并研究了这篇有用的文章。

这篇文章的作者提到如下:

09避免使用视图 视图会降低LINQ查询性能的成本。这些都是缓慢的性能,并影响很大的性能。因此,避免在LINQ实体中使用视图。

我只是熟悉数据库上下文中的view。因为我不明白这句话:他指的是什么观点?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-01-24 07:54:57

这是一篇文章中相当严肃的微观优化。

我不会把它当作个人的福音,因为我曾与EF合作过很多次。当然,这些事情可能很重要,但总的来说,这是相当快的。

如果您有一个复杂的视图,然后在该视图上执行进一步的LINQ,那么当然,它可能会导致一些缓慢的表现,但我不会打赌。

这篇文章甚至没有任何长条旗!

如果性能对您的程序来说是一个严重的问题,那么缩小哪些查询是慢的,并在这里发布它们,看看SO社区是否可以帮助您优化查询。如果你问我的话,这比所有的微观优化要好得多。

票数 3
EN

Stack Overflow用户

发布于 2014-01-24 12:45:23

这取决于,虽然很少在很大程度上。

假设我们看到了这样的景象:

代码语言:javascript
复制
CREATE VIEW TestView
AS
Select A.x, B.y, B.z
FROM A JOIN B on A.id = B.id

我们为此创建了一个实体映射。

我们还假设B.id是绑定的,因此它是不可空的,并且与A.id有一个外键关系-也就是说,每当有B行时,总是至少有一个对应的A。

现在,如果我们可以做一些类似from t in context.TestView where t.x == 3而不是from a in context.A join b in context.B on a.id equals b.id where a.x == 3 select new {a.x, b.y, b.z}的事情。

我们可以预期前者转换为SQL的速度会稍微快一些,因为这是一个稍微简单一些的查询(从Linq和SQL角度来看)。

我们可以预期后者将从一个SQL查询转换为一个SQLServer (或其他什么)内部查询,速度会稍微快一些。

我们可以预期,这个内部查询几乎是相同的,除非有什么事情变得有点奇怪。因此,我们希望那时的表现是相同的。

总之,他们之间没有太多的选择。如果我必须下一次赌注,我会在这上面下注,尤其是在第一次打电话的时候,我的视野会稍微快一些,但我不会下太多的赌注。

现在让我们考虑一下(from t in context.TestView select t.z).Distinct()。对(from b in context.B select b.z).Distinct().

这两者都应该变成一个非常简单的SELECT DISTINCT z FROM ...。

这两种方法都应该转化为表B的表扫描或索引扫描。

第一个可能不是(查询计划中的缺陷),但这将是令人惊讶的。(快速检查类似的视图确实会发现SQLServer忽略了无关的表)。

第一种方法可能需要稍长的时间来生成查询计划,因为必须推导出A.id上的联接与此无关这一事实。但是数据库服务器擅长于这类事情;这是一套计算机科学和问题,已经做了几十年的工作。

如果我不得不下一个赌注,我会把赌注押在观景上,使事情变得更慢,尽管我会更多地押注于它是如此微小的差别,以至于它消失了。对这两种查询的实际测试发现,这两种查询处于相同的差异范围内(即,这两种查询的不同时间范围相互重叠)。

在本例中,linq查询对SQL生成的影响为零(在这一点上它们实际上是相同的,但名称不同)。

让我们考虑一下是否在该视图上有一个触发器,以便插入或删除执行等效的插入或删除。在这里,我们将从使用一个SQL查询而不是使用两个(或更多)SQL查询中获得一些好处,并且更容易确保它发生在单个事务中。因此,在这种情况下,视图略有增加。

现在,让我们考虑一个更复杂的观点:

代码语言:javascript
复制
CREATE VIEW Complicated
AS
Select A.x, B.x as y, C.z, COALESCE(D.f, D.g, E.h) as foo
FROM
A JOIN B on A.r = B.f + 2
JOIN C on COALESCE(A.g, B.x) = C.x
JOIN D on D.flag | C.flagMask <> 0
WHERE EXISTS (SELECT null from G where G.x + G.y = A.bar AND G.deleted = 0)
AND A.deleted = 0 AND B.deleted = 0

我们可以在linq级别完成所有这些工作。如果我们这样做了,随着查询生产的进行,它可能会有点昂贵,尽管这很少是linq查询的最昂贵的部分,尽管编译后的查询可能会平衡这一点。

我倾向于视图是更有效的方法,但如果这是我使用视图的唯一原因,我会分析一下。

现在让我们考虑:

代码语言:javascript
复制
CREATE VIEW AllAncestry
AS
WITH recurseAncetry (ancestorID, descendantID)
AS
(
    SELECT parentID, childID
    FROM Parentage
    WHERE parentID IS NOT NULL

    UNION ALL

    SELECT ancestorID, childID
    FROM recurseAncetry
        INNER JOIN Parentage ON parentID = descendantID
)
SELECT DISTINCT (cast(ancestorID as bigint) * 0x100000000 + descendantID) as id, ancestorID, descendantID
FROM recurseAncetry

从概念上讲,这个视图执行大量的选择;执行一个选择,然后根据该选择的结果递归地执行一个选择,等等,直到它有了所有可能的结果。

在实际执行中,这将转换为两个表扫描和一个懒惰的假脱机。

基于linq的等价物要重得多;实际上,您最好要么调用等效的原始SQL,要么将表加载到内存中,然后在C#中生成完整的图(但请注意,这将是对基于此的查询的浪费,而这些查询并不需要所有的东西)。

总之,在这里使用一个视图将是一个很大的节省。

总之,使用视图通常对性能的影响是可以忽略不计的,而且这种影响可以是任意一种。使用带有触发器的视图可以获得轻微的性能胜利,并通过强制在单个事务中实现数据完整性而变得更容易。在CTE中使用视图可以获得很大的性能胜利。

使用或避免视图的非性能原因是:

  1. 视图的使用隐藏了代码中与该视图相关的实体和与基础表相关的实体之间的关系。这是不好的,因为你的模型现在在这方面是不完整的。
  2. 如果视图在其他应用程序中使用,那么您将与其他应用程序更加一致,利用已经尝试过并经过测试的代码,并自动处理视图实现的更改。
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21327147

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档