所以...... 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)
答案 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的票证。