ПРИМЕЧАНИЕ. Я привожу здесь подробные сведения о настройке Azure, но я не уверен, что это будет решение на основе Azure. Это может быть проблема, которая может быть решена на уровне C #, Entity Framework или SQL.
У меня есть веб-приложение .NET, работающее в службе приложений Azure, использующее Entity Framework для доступа к базе данных SQL Azure SQL на уровне цены Standard S1 (20 DTU). В 99% случаев приложение использует менее 1% DTU в базе данных SQL. Однако, когда кто-то входит в портал администратора приложения и запускает определенный отчет, он выполняет запрос, который требует очень много ресурсов и занимает очень много времени - более минуты - с которым мы не можем жить. Этот отчет запускается только несколько раз в неделю. Я попытался расширить базу данных SQL и обнаружил, что неудивительно, что при более высоких планах время выполнения достигает некоторого разумного уровня. На стандартном S4 (200 DTU) время выполнения падает до 20 секунд, что не является идеальным, но сейчас я могу жить с этим. Однако не имеет смысла платить за уровень S4, когда в 99% случаев он будет использовать лишь долю процента DTU. Любые идеи о том, как я могу уменьшить время выполнения запроса или масштабировать только при необходимости?
Код Entity Framework, используемый для этого отчета:
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
Примерное количество строк в каждой из соединяемых таблиц:
Таблица сессий: 2 миллиона строк
Таблица устройств: 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, изменения кода. Похоже, что существует модель потребления для базы данных SQL Azure, которая может помочь мне, если она существует.