我们有一个BI服务,该服务在分别具有60k和140k行的2个表上运行一组查询。该数据库是S2类(50 DTU)单一数据库Azure SQL数据库。
示例查询如下:
select distinct [t1].[DefinitionId], isnull([t3].[Count], 0) as Count, [t1].[Type]
from [bi].[Trigger] as [t1]
left join (
select [t2].[DefinitionId], count(1) as [Count]
from [bi].[Trigger] as [t2]
inner join [bi].[Recipient] as [r] on [t2].[RecipientId] = [r].[RecipientId] and [r].[IsDeleted] = 0 and [r].[IsDeactivated] = 0 and [t2].[DeliveryStatus] = @deliveryStatus
where [t2].[CampaignId] = @campaignId
group by [t2].[DefinitionId], [t2].[Type]
) as [t3] on [t1].[DefinitionId] = [t3].[DefinitionId]
where [t1].[CampaignId] = @campaignId
正确的索引位于[Trigger]和[Recipient]表上:
CREATE INDEX [IX_Trigger_CampaignId] on [bi].[Trigger] ([CampaignId]) INCLUDE ([DefinitionId],[Type]);
CREATE INDEX [IX_Trigger_CampaignIdDeliveryStatus] on [bi].[Trigger] ([CampaignId],[DeliveryStatus]) INCLUDE ([DefinitionId],[Type],[RecipientId]);
CREATE INDEX [IX_Recipient_CampaignId] ON [bi].[Recipient] ([CampaignId]);
CREATE INDEX [IX_Recipient_RecipientIdActive] ON [bi].[Recipient] ([RecipientId],[IsDeactivated],[IsDeleted]);
CREATE INDEX [IX_Recipient_Active] ON [bi].[Recipient] ([IsDeactivated],[IsDeleted]) INCLUDE ([RecipientId]);
使用Entity Framework Core执行查询,如下所示:
return await _dbContext
.TriggerCounts
.FromSql(sqlTriggerCountByDeliveryStatus, new SqlParameter("@campaignId", campaignId), new SqlParameter("@deliveryStatus", deliveryStatus))
.ToArrayAsync(ct);
此查询的响应时间从10毫秒到有时超过30秒(有时只是超时)不等。从Azure Data Studio Shell运行此查询时,它在200ms内始终返回。
获得此查询的解释计划不包括任何全表/索引扫描,也不建议配置其他索引。
据我们所知,这些查询是作为单进程管道的一部分按顺序运行的,其中命令一次被出队。
什么可以解释这些截然不同的结果?
编辑1
一个难题出现了。在Data Studio Shell中执行时,运行上述查询的以下两种变体会产生截然不同的响应时间:
1。
declare @campaignId nvarchar(128) = '3155373858485711912C4FC8383061F44488933B942FBF81BB1';
declare @deliveryStatus nvarchar(32) = 'delivered';
select distinct [t1].[DefinitionId], isnull([t3].[Count], 0) as Count, [t1].[Type]
from [bi].[Trigger] as [t1]
left join (
select [t2].[DefinitionId], count(1) as [Count]
from [bi].[Trigger] as [t2]
inner join [bi].[Recipient] as [r] on [t2].[RecipientId] = [r].[RecipientId] and [r].[IsDeleted] = 0 and [r].[IsDeactivated] = 0 and [t2].[DeliveryStatus] = @deliveryStatus
where [t2].[CampaignId] = @campaignId
group by [t2].[DefinitionId], [t2].[Type]
) as [t3] on [t1].[DefinitionId] = [t3].[DefinitionId]
where [t1].[CampaignId] = @campaignId
2。
declare @campaignId nvarchar(128) = '3155373858485711912C4FC8383061F44488933B942FBF81BB1';
declare @deliveryStatus nvarchar(32) = 'delivered';
select distinct [t1].[DefinitionId], isnull([t3].[Count], 0) as Count, [t1].[Type]
from [bi].[Trigger] as [t1]
left join (
select [t2].[DefinitionId], count(1) as [Count]
from [bi].[Trigger] as [t2]
inner join [bi].[Recipient] as [r] on [t2].[RecipientId] = [r].[RecipientId] and [r].[IsDeleted] = 0 and [r].[IsDeactivated] = 0 and [t2].[DeliveryStatus] = 'delivered'
where [t2].[CampaignId] = '3155373858485711912C4FC8383061F44488933B942FBF81BB1'
group by [t2].[DefinitionId], [t2].[Type]
) as [t3] on [t1].[DefinitionId] = [t3].[DefinitionId]
where [t1].[CampaignId] = '3155373858485711912C4FC8383061F44488933B942FBF81BB1'
变体1始终在200毫秒以下返回,而变体2始终在10 s左右返回。
变体2的响应时间与我们在Azure中获得的响应时间更加一致。我们是否可以使用EF Core正确运行查询?
编辑2
以下是查询计划:
另一个有趣的元素是query1在11:30:05超时,但是在30秒后的11时30分以相同的参数运行了<300ms ...