Eu tenho esta declaração de exclusão
delete from dbo.HighSchoolGradeLevel where Id=@P0
Este é o plano de execução
https://www.brentozar.com/pastetheplan/?id=H1qzvl3nW
quando o aplicativo está ocupado e há muitas exclusões chegando, o desempenho fica tão ruim, minhas perguntas são.
Como fazer com que essa exclusão tenha um desempenho melhor?
por que a memória concedida é tão alta, ela rouba a memória do buffer pool?
Nota: há uma cascata de exclusão nas 2 tabelas Highschoolcourse e highschoolgrade.
CREATE TABLE [dbo].[HighSchoolCourseGrade](
[Id] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[TermSubTypeLkupId] [int] NULL,
[Grade] [varchar](50) NULL,
[GradePoint] [float] NULL,
[CourseId] [int] NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[UpdatedDate] [datetime] NOT NULL,
[CourseUnits] [float] NULL,
CONSTRAINT [PK_HighSchoolCourseGrade] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
/****** Object: Index [ix_HighSchoolCourseGrade_CourseId_includes] Script Date: 10/11/2017 4:33:38 PM ******/
CREATE NONCLUSTERED INDEX [ix_HighSchoolCourseGrade_CourseId_includes] ON [dbo].[HighSchoolCourseGrade]
(
[CourseId] ASC
)
INCLUDE ( [Id],
[TermSubTypeLkupId],
[Grade],
[GradePoint],
[CreatedDate],
[UpdatedDate],
[CourseUnits]) 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]
GO
ALTER TABLE [dbo].[HighSchoolCourseGrade] WITH CHECK ADD CONSTRAINT [FK_HighSchoolCourseGrade_CourseId] FOREIGN KEY([CourseId])
REFERENCES [dbo].[HighSchoolCourse] ([Id])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[HighSchoolCourseGrade] CHECK CONSTRAINT [FK_HighSchoolCourseGrade_CourseId]
GO
CREATE TABLE [dbo].[HighSchoolCourse](
[Id] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[CourseName] [varchar](200) NULL,
[CourseTypeLkupId] [int] NULL,
[EntryTypeLkupId] [int] NULL,
[SubjectKey] [int] NULL,
[GradeLevelId] [int] NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[UpdatedDate] [datetime] NOT NULL,
[TotalCourseUnit] [float] NULL,
[TotalGradePoint] [float] NULL,
CONSTRAINT [PK_HighSchoolCourse] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
/****** Object: Index [ix_HighSchoolCourse_GradeLevelId_includes] Script Date: 10/11/2017 4:32:58 PM ******/
CREATE NONCLUSTERED INDEX [ix_HighSchoolCourse_GradeLevelId_includes] ON [dbo].[HighSchoolCourse]
(
[GradeLevelId] ASC,
[SubjectKey] ASC
)
INCLUDE ( [Id],
[CourseName],
[CourseTypeLkupId],
[EntryTypeLkupId],
[CreatedDate],
[UpdatedDate],
[TotalCourseUnit],
[TotalGradePoint]) 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]
GO
ALTER TABLE [dbo].[HighSchoolCourse] WITH CHECK ADD CONSTRAINT [FK_HighSchoolCourse_GradeLevelId] FOREIGN KEY([GradeLevelId])
REFERENCES [dbo].[HighSchoolGradeLevel] ([Id])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[HighSchoolCourse] CHECK CONSTRAINT [FK_HighSchoolCourse_GradeLevelId]
GO
Isso é de sp_blitzcahce
Atualizar
Encontrei este Delete no Query Store, eram 3 planos e forcei o SQL a usar um plano diferente. Estou me perguntando por que o SQL opta por usar o plano de execução mais caro?
Tente adicionar
Id
como uma das colunas-chave deix_HighSchoolCourseGrade_CourseId_includes
. Isso pode ajudar com as necessidades de classificação adicionais, bem como com a chave estrangeira.Se você puder alterar a chave estrangeira, remova as ações em cascata e faça suas exclusões das tabelas de referência primeiro. Chaves estrangeiras em cascata usam bloqueios serializáveis nos bastidores e, ao excluir grandes quantidades de dados, podem causar cenários de bloqueio incorretos.
Se você puder alterar o código, faça suas exclusões via proc armazenado. Isso é mais fácil do que criar guias de plano para o código do aplicativo . Ele oferece muitas opções de ajuste para ajudar a diminuir as concessões de memória também. Você pode usar MAX_GRANT_PERCENT entre outras coisas (recompilar, etc.) para obter um plano mais apropriado.
No entanto, fazer a alteração do índice deve ser seu primeiro esforço.