如何让EF6生成高效的(...)查询

时间:2016-12-15 21:39:26

标签: c# entity-framework linq linq-to-entities

所以...... EF6正在创建一个非常低效的查询。我有一个查询违反了具有三种不同类型地址的数据源。我有一个地址ID列表,可能是用户尝试使用的新副本的重复。理想情况下,我希望此查询检查几个地址ID中的任何一个是否在给定的一组ID中。目前此查询:

return await _tickets.Where(t =>
    t.Metadata is SIFTEscalationMetadata && (
        addesses.Any(a => a == (t.Metadata as SIFTEscalationMetadata).Address.Id) ||
        addesses.Any(a => a == (t.Metadata as SIFTEscalationMetadata).AddressEntered.Id) ||
        addesses.Any(a => a == (t.Metadata as SIFTEscalationMetadata).CleanedAddress.Id))).ToArrayAsync();

正在成为这个:

SELECT 
    [Project1].[TicketId] AS [TicketId], 
    [Project1].[TicketType] AS [TicketType], 
    [Project1].[Opened] AS [Opened], 
    [Project1].[Closed] AS [Closed], 
    [Project1].[Modified] AS [Modified], 
    [Project1].[EscalationStatusText] AS [EscalationStatusText], 
    [Project1].[QualificationStatusText] AS [QualificationStatusText], 
    [Project1].[ProductsText] AS [ProductsText], 
    [Project1].[Cancelled] AS [Cancelled], 
    [Project1].[CancellationReason_Id] AS [CancellationReason_Id], 
    [Project1].[CreatedBy_Id] AS [CreatedBy_Id], 
    [Project1].[Metadata_Id] AS [Metadata_Id], 
    [Project1].[NotesContainer_Id] AS [NotesContainer_Id]
    FROM ( SELECT 
        [Extent1].[TicketId] AS [TicketId], 
        [Extent1].[TicketType] AS [TicketType], 
        [Extent1].[Opened] AS [Opened], 
        [Extent1].[Closed] AS [Closed], 
        [Extent1].[Modified] AS [Modified], 
        [Extent1].[EscalationStatusText] AS [EscalationStatusText], 
        [Extent1].[QualificationStatusText] AS [QualificationStatusText], 
        [Extent1].[ProductsText] AS [ProductsText], 
        [Extent1].[Cancelled] AS [Cancelled], 
        [Extent1].[CancellationReason_Id] AS [CancellationReason_Id], 
        [Extent1].[CreatedBy_Id] AS [CreatedBy_Id], 
        [Extent1].[Metadata_Id] AS [Metadata_Id], 
        [Extent1].[NotesContainer_Id] AS [NotesContainer_Id], 
        CASE WHEN ([Extent2].[TicketMetadataID] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE '2X0X' END AS [C1]
        FROM  [dbo].[Tickets] AS [Extent1]
        LEFT OUTER JOIN [dbo].[TicketMetadata] AS [Extent2] ON ([Extent2].[Discriminator] = N'SIFTEscalationMetadata') AND ([Extent1].[Metadata_Id] = [Extent2].[TicketMetadataID])
    )  AS [Project1]
    WHERE ([Project1].[C1] LIKE '2X0X%') AND (( EXISTS (SELECT 
        1 AS [C1]
        FROM   (SELECT 
            486524 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
        UNION ALL
            SELECT 
            486525 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable2]
        UNION ALL
            SELECT 
            486526 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable3]
        UNION ALL
            SELECT 
            508376 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable4]
        UNION ALL
            SELECT 
            508377 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable5]
        UNION ALL
            SELECT 
            508378 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable6]) AS [UnionAll5]
        LEFT OUTER JOIN  (SELECT 
            [Extent3].[Address_Id] AS [Address_Id], 
            '2X0X' AS [C1]
            FROM [dbo].[TicketMetadata] AS [Extent3]
            WHERE ([Extent3].[Discriminator] = N'SIFTEscalationMetadata') AND ([Project1].[Metadata_Id] = [Extent3].[TicketMetadataID]) ) AS [Project8] ON 1 = 1
        WHERE [UnionAll5].[C1] = (CASE WHEN ([Project8].[C1] LIKE '2X0X%') THEN [Project8].[Address_Id] END)
    )) OR ( EXISTS (SELECT 
        1 AS [C1]
        FROM   (SELECT 
            486524 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable7]
        UNION ALL
            SELECT 
            486525 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable8]
        UNION ALL
            SELECT 
            486526 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable9]
        UNION ALL
            SELECT 
            508376 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable10]
        UNION ALL
            SELECT 
            508377 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable11]
        UNION ALL
            SELECT 
            508378 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable12]) AS [UnionAll10]
        LEFT OUTER JOIN  (SELECT 
            [Extent4].[AddressEntered_Id] AS [AddressEntered_Id], 
            '2X0X' AS [C1]
            FROM [dbo].[TicketMetadata] AS [Extent4]
            WHERE ([Extent4].[Discriminator] = N'SIFTEscalationMetadata') AND ([Project1].[Metadata_Id] = [Extent4].[TicketMetadataID]) ) AS [Project16] ON 1 = 1
        WHERE [UnionAll10].[C1] = (CASE WHEN ([Project16].[C1] LIKE '2X0X%') THEN [Project16].[AddressEntered_Id] END)
    )) OR ( EXISTS (SELECT 
        1 AS [C1]
        FROM   (SELECT 
            486524 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable13]
        UNION ALL
            SELECT 
            486525 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable14]
        UNION ALL
            SELECT 
            486526 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable15]
        UNION ALL
            SELECT 
            508376 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable16]
        UNION ALL
            SELECT 
            508377 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable17]
        UNION ALL
            SELECT 
            508378 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable18]) AS [UnionAll15]
        LEFT OUTER JOIN  (SELECT 
            [Extent5].[CleanedAddress_Id] AS [CleanedAddress_Id], 
            '2X0X' AS [C1]
            FROM [dbo].[TicketMetadata] AS [Extent5]
            WHERE ([Extent5].[Discriminator] = N'SIFTEscalationMetadata') AND ([Project1].[Metadata_Id] = [Extent5].[TicketMetadataID]) ) AS [Project24] ON 1 = 1
        WHERE [UnionAll15].[C1] = (CASE WHEN ([Project24].[C1] LIKE '2X0X%') THEN [Project24].[CleanedAddress_Id] END)
    ))) 

让EF在这里生成更好的查询的最佳方法是什么?如果可以这样做会很好:

SELECT ...
WHERE Address_Id in(486524, 486525, 486526, 508376, 508377, 508378)
      OR AddressEntered_Id in(486524, 486525, 486526, 508376, 508377, 508378)
      OR CleanedAddress_Id in(486524, 486525, 486526, 508376, 508377, 508378)

2 个答案:

答案 0 :(得分:4)

由于@Cory指出Contains扩展方法已在SQL中转换为IN,因此您应该使用它而不是转换为Any的{​​{1}}:< / p>

EXIST

此外,您还应使用return await _tickets.OfType<SIFTEscalationMetadata>() .Where(t =>addesses.Contains(t.Address.Id) || addesses.Contains(t.AddressEntered.Id) || addesses.Contains(t.CleanedAddress.Id)).ToArrayAsync(); 扩展方法仅获取OfType个实体

答案 1 :(得分:0)

从您的代码示例中我假设以下内容。

_tickets是一个类的一系列项目,让我们说一个Ticket。并且序列中的每个项目都有一个属性MetaData。 MetaData的返回值可能是也可能不是SIFTEscalationMetaData。 (这是真的吗?或者每个MetaData都是SIFTEscalationMetaData?)

当属性MetaData的值是SIFTEscalationMetaData时,您确定属性Ticket.MetaData至少具有三个其他非空属性:Address,AddressEntered和CleanedAddress。此外,您确定这三个属性不会返回NULL,并且它们三个都具有属性Id。

此外,您还有一个序列addesses,其中每个元素与属性Id的类型相同。我不知道Id的类型,但我们假设它是IdType,可能是int或字符串之类

显然,您只需要来自_tickets序列的门票,其中属性MetaData是SIFTEscalationMetaData,并且至少有一个Ticket.MetaData.Address,Ticket.MetaData.AddressEntered或Ticke.MetaData.CleanedAddress的Id值是在addesses的集合。

IEnumerable<Ticket> result = _tickets
    // first remember the ticket and convert the MetaData
    // to either null or a SIFTEscalationMetadata
    .Select(t => new
    {
        Ticket = t,
        MetaData = t.Metadata as SIFTEscalationMetadata,
    })
    // now take only those tickets where the metadata is not null
    .Where(t => t.MetaData != null)
    // and select from the remaining tickets the Ids you want to check
    .Select(t => new
    {
        Ticket = t.Ticket,
        Ids = new IdType[]
        {
            t.MetaData.Address.Id,
            t.MetaDate.AddressEntered.Id,
            t.MetaData.CleanedAddress.Id,
        },
     })
     // now take only those items where the intersection of the Ids and 
     // addesses has any elements
     .Where(t => addess.Interset(t.Ids).Any())
     .Select(t => t.Ticket);

优化在中间选择到匿名类型。匿名类型将成为SQL变量。每张票只能转换为SIFTEscalationMetaData一次。检查是否有任何ID是adadses只进行一次,仅适用于具有正确MetaData的票证。