Linq 实体框架似乎不必要地连接同一个表两次
更新这可能已经修复: 针对我的实体的相当简单的LINQ语句会导致不必要的复杂SQL。稍后将介绍更多信息,以下是设置: 表格 出版Linq 实体框架似乎不必要地连接同一个表两次,linq,entity-framework,Linq,Entity Framework,更新这可能已经修复: 针对我的实体的相当简单的LINQ语句会导致不必要的复杂SQL。稍后将介绍更多信息,以下是设置: 表格 出版 PublicationId(主键) TopicId(fk到主题表) ReceiptCount(针对查询性能进行非规范化) 插入日期 收据 接收方ID(pk) PublicationId(fk到上表) 插入日期 LINQ var query = from r in context.Receipts.Include("Publication")
- PublicationId(主键)
- TopicId(fk到主题表)
- ReceiptCount(针对查询性能进行非规范化)
- 插入日期
- 接收方ID(pk)
- PublicationId(fk到上表)
- 插入日期
var query = from r in context.Receipts.Include("Publication")
where r.DateInserted < lagDate
&& r.ReceiptId > request.AfterReceiptId
&& r.Publication.TopicId == topicEntity.TopicId
&& r.Publication.ReceiptCount > 1
select r;
var query=context.Receipts.Include(“发布”)中的r
其中r.DateInsertedrequest.AfterReceiptId
&&r.Publication.TopicId==topicEntity.TopicId
&&r.Publication.ReceiptCount>1
选择r;
SQL
exec sp_executesql N'SELECT TOP (25)
[Project1].[ReceiptId] AS [ReceiptId],
[Project1].[PublicationId] AS [PublicationId],
[Project1].[DateInserted] AS [DateInserted],
[Project1].[DateReceived] AS [DateReceived],
[Project1].[PublicationId1] AS [PublicationId1],
[Project1].[PayloadId] AS [PayloadId],
[Project1].[TopicId] AS [TopicId],
[Project1].[BrokerType] AS [BrokerType],
[Project1].[DateInserted1] AS [DateInserted1],
[Project1].[DateProcessed] AS [DateProcessed],
[Project1].[DateUpdated] AS [DateUpdated],
[Project1].[PublicationGuid] AS [PublicationGuid],
[Project1].[ReceiptCount] AS [ReceiptCount]
FROM ( SELECT
[Extent1].[ReceiptId] AS [ReceiptId],
[Extent1].[PublicationId] AS [PublicationId],
[Extent1].[DateInserted] AS [DateInserted],
[Extent1].[DateReceived] AS [DateReceived],
[Extent3].[PublicationId] AS [PublicationId1],
[Extent3].[PayloadId] AS [PayloadId],
[Extent3].[TopicId] AS [TopicId],
[Extent3].[BrokerType] AS [BrokerType],
[Extent3].[DateInserted] AS [DateInserted1],
[Extent3].[DateProcessed] AS [DateProcessed],
[Extent3].[DateUpdated] AS [DateUpdated],
[Extent3].[PublicationGuid] AS [PublicationGuid],
[Extent3].[ReceiptCount] AS [ReceiptCount]
FROM [dbo].[Receipt] AS [Extent1]
INNER JOIN [dbo].[Publication] AS [Extent2] ON [Extent1].[PublicationId] = [Extent2].[PublicationId]
LEFT OUTER JOIN [dbo].[Publication] AS [Extent3] ON [Extent1].[PublicationId] = [Extent3].[PublicationId]
WHERE ([Extent2].[ReceiptCount] > 1) AND ([Extent1].[DateInserted] < @p__linq__0) AND ([Extent1].[ReceiptId] > @p__linq__1) AND ([Extent2].[TopicId] = @p__linq__2)
) AS [Project1]
ORDER BY [Project1].[ReceiptId] ASC',N'@p__linq__0 datetime,@p__linq__1 int,@p__linq__2 int',@p__linq__0='2012-09-05 19:39:21:510',@p__linq__1=4458824,@p__linq__2=90
exec sp_executesql N'选择顶部(25)
[Project1]。[ReceiptId]作为[ReceiptId],
[Project1]。[PublicationId]作为[PublicationId],
[Project1]。[DateInserted]作为[DateInserted],
[Project1][DateReceived]作为[DateReceived],
[Project1][PublicationId1]作为[PublicationId1],
[Project1]。[PayloadId]作为[PayloadId],
[Project1]。[TopicId]作为[TopicId],
[Project1]。[BrokerType]作为[BrokerType],
[Project1]。[DateInserted1]作为[DateInserted1],
[Project1]。[DateProcessed]作为[DateProcessed],
[Project1]。[DateUpdated]为[DateUpdated],
[Project1]。[PublicationGuid]作为[PublicationGuid],
[Project1][ReceiptCount]作为[ReceiptCount]
从(选择
[Extent1]。[ReceiptId]作为[ReceiptId],
[Extent1]。[PublicationId]作为[PublicationId],
[Extent1]。[DateInserted]作为[DateInserted],
[Extent1]。[DateReceived]作为[DateReceived],
[Extent3]。[PublicationId]作为[PublicationId1],
[Extent3]。[PayloadId]作为[PayloadId],
[Extent3]。[TopicId]作为[TopicId],
[Extent3]。[BrokerType]作为[BrokerType],
[Extent3]。[DateInserted]作为[DateInserted1],
[Extent3]。[DateProcessed]作为[DateProcessed],
[Extent3]。[DateUpdate]作为[DateUpdate],
[Extent3]。[PublicationGuid]作为[PublicationGuid],
[Extent3][ReceiptCount]作为[ReceiptCount]
从[dbo].[Receipt]作为[Extent1]
内部联接[dbo].[Publication]作为[Extent1].[PublicationId]=[Extent2].[PublicationId]上的[Extent2]
[Extent1].[PublicationId]=[Extent3].[PublicationId]上的[Extent3]左外部联接[dbo].[Publication]为[Extent3]
其中([Extent2].[ReceiptCount]>1)和([Extent1].[DateInserted]<@p_uulinq_u0)和([Extent1].[ReceiptId]>@p_ulinq_u1)和([Extent2].[TopicId]=@p_ulinq_u2)
)AS[Project1]
由[Project1].[ReceiptId]ASC,N'@p_uLinq_u0 datetime,@p_uLinq_u1 int,@p_uLinq_u2 int',@p_uLinq_u0='2012-09-05 19:39:21:510',@p_uLinq_u1=4458824,@p_uLinq_u2=90订购
问题
发布被加入两次:
.Include(“Publication”)
的where
而导致内部联接.Include(“Publication”)
。。。有什么解决办法吗
我使用的是EF4,但从NuGet抓取了EF5,看看它是否被修复,但它产生了相同的结果(尽管我不知道如何判断我的EDMX是否真的在使用EF5)。不过,还有一个解决办法。它可能不是最优雅的解决方案,但它确实满足了您的需求;它只生成一个连接 更改:
var query = from r in context.Receipts.Include("Publication")
where r.DateInserted < lagDate
&& r.ReceiptId > request.AfterReceiptId
&& r.Publication.TopicId == topicEntity.TopicId
&& r.Publication.ReceiptCount > 1
select r;
我将通过如下更改代码来优化前一个人的答案,这样就不需要连接,这样您就不必知道需要连接哪些列,也不必在连接条件更改时更改LINQ。这本应该是不必要的,但微软目前并不专注于修复其sql代码生成
var query = from pub in context.Publications
from r in pub.Reciepts
where r.DateInserted < lagDate
&& r.ReceiptId > request.AfterReceiptId
&& pub.TopicId == topicEntity.TopicId
&& pub.ReceiptCount > 1
select new {
Receipt = r,
Publication = pub
};
var query=来自context.Publications中的发布
从酒吧里的r收到
其中r.DateInsertedrequest.AfterReceiptId
&&pub.TopicId==topicEntity.TopicId
&&pub.ReceiptCount>1
选择新的{
收据=r,
发布=发布
};
使用临时变量(例如,let
pub=r.Publication)可以避免这种行为
var query=context.Receipts中的r
让pub=r.Publication//使用临时变量
其中r.DateInsertedrequest.AfterReceiptId
&&pub.TopicId==topicEntity.TopicId
&&pub.ReceiptCount>1
选择新建{r,pub};
我认为where和include都在进行连接,并且没有简化为左连接。您应该将此作为EF Codeplex项目的改进发布。然而,我认为这将是相当低的优先级,因为我认为SQL对于这种“甚至”的NHibernate来说是相当有效的。将其视为自动查询生成的特殊性。数据库引擎可能会对其进行优化。“不过观察得不错。@GertArnold它实际上导致了性能问题。”。SQL事件探查器报告的持续时间为700-900毫秒,如果我删除它,我会得到0-6毫秒。男孩!坏消息。看起来它还是需要改进的。@Langdon你要删除哪一个子句?我认为这将被解释为一个内部连接
,而不是左连接
@edze它应该是一个内部连接a内部连接b作为b1左连接b作为b2
(提示此问题的双连接)将永远不会为b2
返回空行,因为所有缺少b
行的a
都已被第一个连接过滤掉。也就是说,同样的想法应该可以在foreach ( var item in query)
{
//see that item.Publication is not null
if(item.Receipt != null && item.Receipt.Publication != null)
{
//do work based on a valid Publication
}
else
{
//do work based on no linked Publication
}
}
var query = from pub in context.Publications
from r in pub.Reciepts
where r.DateInserted < lagDate
&& r.ReceiptId > request.AfterReceiptId
&& pub.TopicId == topicEntity.TopicId
&& pub.ReceiptCount > 1
select new {
Receipt = r,
Publication = pub
};
var query = from r in context.Receipts
let pub = r.Publication // using a temp variable
where r.DateInserted < lagDate
&& r.ReceiptId > request.AfterReceiptId
&& pub.TopicId == topicEntity.TopicId
&& pub.ReceiptCount > 1
select new { r, pub };