注意:我在这里提供了我的Azure设置的详细信息,但我不确定该解决方案是否基于Azure。这可能是可以在C#,实体框架或SQL级别解决的问题。
我在Azure App Service上运行.NET Web应用程序,使用Entity Framework以定价级别标准S1(20 DTU)访问Azure SQL DB。 99%的时间,该应用程序在SQL DB上使用的DTU不到1%。但是,当有人登录应用程序的管理门户并运行特定报告时,它会执行资源密集型的查询,并且需要很长时间 - 超过一分钟 - 这是我们无法忍受的。该报告每周只运行几次。我已经尝试过扩展SQL数据库并且发现 - 不出所料 - 在更高的计划中,执行时间达到了一个合理的水平。在标准S4(200 DTU),执行时间下降到20秒,这是不理想的,但我现在可以忍受。但是,当99%的时间只使用DTU的一小部分时,支付S4级是没有意义的。关于如何减少查询执行时间或仅在需要时进行扩展的任何想法?
此报告使用的实体框架代码为:
class MyAppModelContainer : DbContext
{
public virtual ObjectResult<GetOrganizationList_Result> GetOrganizationList()
{
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<GetOrganizationList_Result>("GetOrganizationList");
}
}
用于检索结果的模型是:
public partial class GetOrganizationList_Result
{
public int id { get; set; }
public string Name { get; set; }
public Nullable<int> DeviceCounts { get; set; }
public Nullable<int> EmailCounts { get; set; }
}
存储过程是:
CREATE PROCEDURE [dbo].[GetOrganizationList]
AS
BEGIN
SELECT o.Id,o.Name,COUNT(distinct s.DeviceId) as DeviceCounts, COUNT(distinct d.userid) as EmailCounts
FROM Sessions s
INNER JOIN Devices d on d.Id = s.DeviceId
RIGHT OUTER JOIN Organizations o on o.id=s.OrganizationId
GROUP BY o.Id,Name
END
每个连接表中的近似行数: 会话表:200万行 设备表:166,000行 用户表:88,000行
以下是表定义和索引:
CREATE TABLE [dbo].[Sessions] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[DeviceId] INT NULL,
[StartTime] DATETIME NOT NULL,
[OrganizationId] INT NOT NULL,
CONSTRAINT [PK_Sessions] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_DeviceSession] FOREIGN KEY ([DeviceId]) REFERENCES [dbo].[Devices] ([Id]),
CONSTRAINT [FK_OrganizationSession] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organizations] ([Id])
);
CREATE NONCLUSTERED INDEX [IX_FK_DeviceSession]
ON [dbo].[Sessions]([DeviceId] ASC);
CREATE NONCLUSTERED INDEX [IX_FK_OrganizationSession]
ON [dbo].[Sessions]([OrganizationId] ASC);
CREATE NONCLUSTERED INDEX [IX_Sessions_OrganizationId_Include_DeviceId]
ON [dbo].[Sessions]([OrganizationId] ASC)
INCLUDE([DeviceId]);
CREATE NONCLUSTERED INDEX [IX_Sessions_OrganizationId_DeviceId] ON [dbo].[Sessions]
(
[DeviceId] ASC,
[OrganizationId] ASC,
[StartTime] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
CREATE TABLE [dbo].[Devices] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[UserId] INT NULL,
[MACAddress] NCHAR (12) NOT NULL,
CONSTRAINT [PK_Devices] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_UserDevice] FOREIGN KEY ([UserId]) REFERENCES [dbo].[Users] ([Id]),
CONSTRAINT [IX_Unique_MACAddress] UNIQUE NONCLUSTERED ([MACAddress] ASC)
);
CREATE NONCLUSTERED INDEX [IX_FK_UserDevice]
ON [dbo].[Devices]([UserId] ASC);
CREATE TABLE [dbo].[Users] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Email] NVARCHAR (250) NOT NULL,
[Sex] TINYINT NOT NULL,
[Age] SMALLINT NOT NULL,
[PhoneNumber] NCHAR (10) NOT NULL DEFAULT '' ,
[Name] NVARCHAR(100) NOT NULL DEFAULT '',
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [IX_Unique_Email_PhoneNumber] UNIQUE NONCLUSTERED ([Email] ASC, [PhoneNumber] ASC)
);
我每周都会重建索引并更新统计信息。 Azure SQL DB没有性能建议。
有关如何解决此问题的任何想法,而不是简单地投入更多的Azure硬件?我对包括Azure级别更改,SQL更改,代码更改在内的任何内容持开放态度。似乎没有Azure SQL DB的定价消费模型,如果它存在,这可能对我有所帮助。
答案 0 :(得分:0)
我建议您创建以下索引或将缺少的列添加到退出的索引中。
CREATE NONCLUSTERED INDEX [NIX_Session_Device_OrganizationId]
ON [dbo].[Sessions] ([DeviceId] , [OrganizationId]);
CREATE NONCLUSTERED INDEX [NIX_Device_ID_UserID]
ON [dbo].[Devices] ([Id], [userid]);
CREATE NONCLUSTERED INDEX [NIX_Organizations]
ON [dbo].[Organizations] ([Id] , [Name]);
200 DTU不是一个大数字,2oo DTU意味着你已经在S4服务水平,任何以上将使你进入S6。
首先尝试使用适当的索引调整查询,一旦完成,然后开始查看DTU,并且真的对于关键任务系统我更愿意使用vCore
定价模型,而不是使用{的blackbox { {1}}。
答案 1 :(得分:0)
我会创建一个非聚集的列存储索引。你正在进行聚合查询。这非常适合您的情况。它会影响插入和插入有些更新,所以你会想要随着时间的推移进行测试,但这是使查询运行得更快的正确方法:
CREATE NONCLUSTERED COLUMNSTORE INDEX ixtest
ON dbo.Organizations
(
id,
Name --plus whatever other columns are in the table
);
我使用您的脚本设置了一个小测试,查询从17ms到6ms。读数从几千下降到大约十二。
你没有包含组织的定义,所以我只是把它弄掉了。您需要确保在列存储索引中包含所有列(这是最佳实践)。