Я использую nHibnerate в своем веб-приложении, и у меня есть проблема с использованием индексов в сгенерированном sp_execute. Моя таблица имеет 210 миллионов записей, и запрос выполняется очень медленно.sp_executesql не использует индекс?
Во-первых, возникла проблема с созданным типом столбца «kolumna1». В базе данных у меня есть столбец varchar, но nHibernate сгенерирован nvarchar. Я обманул это, добавив специальный атрибут в код, который принудительно использовал varchar. После этого трюк sp_executed начал использовать индексы, и все было правильно. Теперь проблема в том, что sp_executesql занимает 10 минут. Когда я проверил обычный запрос (без sp_executesql), ему потребовалось всего 1 с. Я проверил планы выполнения для обоих: sp_executesql не использовал индекс, а обычный запрос использовал индекс. Без изменения индекса я изменил обратный varchar на nvarchar и sp_execute закончил в 1s (используемый индекс). Кто-нибудь понял, где я совершил ошибку? почему план исполнения отличается для таких небольших изменений? И как это исправить?
Здесь я прилагаю больше кода. На всякий случай, если кому-то это понадобится.
sp_executesql с VARCHAR (8000)
exec sp_executesql N'SELECT count(*) as y0_ FROM tabela1 this_ WHERE ((this_.kolumna2 >= @p0 and this_.kolumna2 <= @p1)) and
(this_.kolumna3 in (@p2, @p3) and this_.kolumna1 like @p4)',N'@p0 datetime,@p1 datetime,@p2 int,@p3 int,@p4 varchar(8000)',
@p0='2013-01-08 14:38:00' ,@p1='2013-02-08 14:38:00',@p2=341,@p3=342,@p4='%501096109%'
sp_executesql с NVARCHAR (4000)
exec sp_executesql N'SELECT count(*) as y0_ FROM tabela1 this_ WHERE ((this_.kolumna2 >= @p0 and this_.kolumna2 <= @p1)) and
(this_.kolumna3 in (@p2, @p3) and this_.kolumna1 like @p4)',N'@p0 datetime,@p1 datetime,@p2 int,@p3 int,@p4 nvarchar(4000)',
@p0='2013-01-08 14:38:00' ,@p1='2013-02-08 14:38:00',@p2=341,@p3=342,@p4='%501096109%'
Самое смешное, что в SQL Profiler как запрос дает такой же reuslt:
exec sp_executesql N'SELECT count(*) as y0_ FROM tabela1 this_
WHERE this_.kolumna3 in (@p2, @p3) and ((this_.kolumna2 >= @p0 and this_.kolumna2 <= @p1))
and (this_.kolumna1 like @p4)',N'@p0 datetime,@p1 datetime,@p2 int,@p3 int,@p4 varchar(8000)',
@p0='2013-01-08 14:38:00' ,@p1='2013-02-08 14:38:00',@p2=341,@p3=342,@p4='%501096109%'
--Declare @p0 datetime
--set @p0 = '2013-01-08 14:38:00'
--Declare @p1 datetime
--set @p1 = '2013-02-08 14:38:00'
--Declare @p2 int
--set @p2 = 341
--Declare @p3 int
--set @p3 = 342
--Declare @p4 varchar(8000)
--set @p4 = '%501096109%'
--SELECT count(*) as y0_
--FROM tabela1 this_
--WHERE ((this_.kolumna2 >= @p0 and
--this_.kolumna2 <= @p1)) and
--(this_.kolumna3 in (@p2, @p3) and this_.kolumna1 like @p4)
Ниже приведены индексы:
CREATE TABLE [dbo].[tabela1](
[id] [bigint] NOT NULL,
[kolumna1] [varchar](128) NOT NULL,
[kolumna2] [datetime] NOT NULL,
[kolumna3] [int] NOT NULL,
CONSTRAINT [PK__tabela1__4F7CD00D] 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]
CREATE NONCLUSTERED INDEX [ind_tabela1_ kolumna2] ON [dbo].[tabela1]
(
[kolumna2] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [ind_ tabela1_ kolumna3] ON [dbo].[ tabela1]
(
[kolumna3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_ tabela1_ kolumna1] ON [dbo].[ tabela1]
(
[kolumna1] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_ tabela1_ kolumna2_ kolumna3] ON [dbo].[ tabela1]
(
[kolumna2] ASC,
[kolumna3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_ tabela1_ kolumna3_ kolumna2_id_ kolumna1] ON [dbo].[ tabela1]
(
[kolumna3] ASC,
[kolumna2] ASC,
[id] ASC,
[kolumna1] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Ниже план выполнения для запроса: SELECT COUNT (*) из [DBO]. [tabela1], где [kolumna1] как N '% 501096109%'
Это может помочь: http://is.gd/RR0fzH –
Этот запрос не сможет использовать поиск индекса для kolumna1. Причина в том, что у вас есть ведущий% в вашем шаблоне. Можете ли вы предоставить запрос non-count, который использует один из ваших индексов? – muhmud
Jamie Ide: Мы уже пробовали этот подход, и у нас есть как varchar в nhibernate, так и databse. –