Здравствуйте, ppvrt, Вы писали:
P>А Вам приходилось оптимизировать работу AWE? В частности, управлять буферами на основе технологии NUMA?
Нет, не приходилось. Зато вот:
I'm running SQL Server 2000 and need to see whether a particular value exists in a table. Which is more efficient, using an EXISTS check or a SELECT COUNT(*)?
A Using the T-SQL EXISTS keyword to perform an existence check is almost always faster than using COUNT(*). EXISTS can stop as soon as the logical test proves true, but COUNT(*) must count every row, even after it knows one row has passed the test.
И, как выясняется, сей вопрос актуален лишь для SQL Server 2000, но не для SQL Server 2005 — который count caм заменяет на exists если видет его в if.
Есть база данных MS SQL 2008.
В таблицах содержится много записей (в некоторых таблицах более 5 млн записей).
Имеется запрос вида:
if exists (select top 1 Column1 from Table1 where Column2 = @value)
begin
...
end
else
begin
...
end
Суть запроса — найти хоть одну строку, в которой значение в ячейке имеет искомое значение.
Так вот, Top 1 сначала находит все строки, удовлетворяющие условию поиска, а потом усекает результаты запроса и выводит клиенту первую строку из результата запроса.
Мне же нужно сделать так, что если нашлась первая строка, удовлетворяющая условию поиска, то дальнейший поиск прекратить. Какой оператор для этого нужно использовать, применительно к MS SQL 2008.
Данный вопрос очень актуален по причине того, что таких запросов на проверку exists (select top 1 ...) в моих хранимых процедурах достаточно много. Кроме того, в процессе выполнения запроса, находится много (порядка 20-30 тысяч) записей, удовлетворяющих условиям поиска.
Здравствуйте, ppvrt, Вы писали:
P>Имеется запрос вида: P>
P>if exists (select top 1 Column1 from Table1 where Column2 = @value)
P>...
P>Так вот, Top 1 сначала находит все строки, удовлетворяющие условию поиска, а потом усекает результаты запроса и выводит клиенту первую строку из результата запроса. P>Мне же нужно сделать так, что если нашлась первая строка, удовлетворяющая условию поиска, то дальнейший поиск прекратить. Какой оператор для этого нужно использовать, применительно к MS SQL 2008.
если есть индекс по "Column2" (или хотя-бы такой где "Column2" на первом месте), то должно работать как ты просишь — должен использоваться INDEX SEEK, и стоп на первой же записи.
Здравствуйте, ppvrt, Вы писали:
P>Есть база данных MS SQL 2008. P>В таблицах содержится много записей (в некоторых таблицах более 5 млн записей).
P>Имеется запрос вида:
P>
P>if exists (select top 1 Column1 from Table1 where Column2 = @value)
P>begin
P>...
P>end
P>else
P>begin
P>...
P>end
P>
P>Суть запроса — найти хоть одну строку, в которой значение в ячейке имеет искомое значение. P>Так вот, Top 1 сначала находит все строки, удовлетворяющие условию поиска, а потом усекает результаты запроса и выводит клиенту первую строку из результата запроса. P>Мне же нужно сделать так, что если нашлась первая строка, удовлетворяющая условию поиска, то дальнейший поиск прекратить. Какой оператор для этого нужно использовать, применительно к MS SQL 2008. P>Данный вопрос очень актуален по причине того, что таких запросов на проверку exists (select top 1 ...) в моих хранимых процедурах достаточно много. Кроме того, в процессе выполнения запроса, находится много (порядка 20-30 тысяч) записей, удовлетворяющих условиям поиска.
Я, конечно, не такой уж большой эксперт (кои встречаются здесь на форуме), однакож ИМХО достаточно сделать
if exists (select Column1 from Table1 where Column2 = @value)
Т.е. убрать top... то что ты спрашиваешь именно так поступает exists. При первом совпадении прекращает работу.
Здравствуйте, Ellin, Вы писали:
E>Здравствуйте, ppvrt, Вы писали:
P>>Есть база данных MS SQL 2008. P>>В таблицах содержится много записей (в некоторых таблицах более 5 млн записей).
P>>Имеется запрос вида:
P>>
P>>if exists (select top 1 Column1 from Table1 where Column2 = @value)
P>>begin
P>>...
P>>end
P>>else
P>>begin
P>>...
P>>end
P>>
P>>Суть запроса — найти хоть одну строку, в которой значение в ячейке имеет искомое значение. P>>Так вот, Top 1 сначала находит все строки, удовлетворяющие условию поиска, а потом усекает результаты запроса и выводит клиенту первую строку из результата запроса. P>>Мне же нужно сделать так, что если нашлась первая строка, удовлетворяющая условию поиска, то дальнейший поиск прекратить. Какой оператор для этого нужно использовать, применительно к MS SQL 2008. P>>Данный вопрос очень актуален по причине того, что таких запросов на проверку exists (select top 1 ...) в моих хранимых процедурах достаточно много. Кроме того, в процессе выполнения запроса, находится много (порядка 20-30 тысяч) записей, удовлетворяющих условиям поиска. E>Я, конечно, не такой уж большой эксперт (кои встречаются здесь на форуме), однакож ИМХО достаточно сделать E>
E>if exists (select Column1 from Table1 where Column2 = @value)
E>
E>Т.е. убрать top... то что ты спрашиваешь именно так поступает exists. При первом совпадении прекращает работу.
Убрал top 1.
Как же так? А почему тогда на плане запроса не меняется значение 'Estimated I/O cost' или 'Estimated CPU cost'?
Что-то же должно изменяться! Время выполнения запроса не уменьшилось.
Здравствуйте, ppvrt, Вы писали:
P>Убрал top 1. P>Как же так? А почему тогда на плане запроса не меняется значение 'Estimated I/O cost' или 'Estimated CPU cost'? P>Что-то же должно изменяться! Время выполнения запроса не уменьшилось.
Здравствуйте, ilya.buchkin, Вы писали:
P>>Имеется запрос вида: P>>
P>>if exists (select top 1 Column1 from Table1 where Column2 = @value)
P>>...
P>>Так вот, Top 1 сначала находит все строки, удовлетворяющие условию поиска, а потом усекает результаты запроса и выводит клиенту первую строку из результата запроса. P>>Мне же нужно сделать так, что если нашлась первая строка, удовлетворяющая условию поиска, то дальнейший поиск прекратить. Какой оператор для этого нужно использовать, применительно к MS SQL 2008.
IB>если есть индекс по "Column2" (или хотя-бы такой где "Column2" на первом месте), то должно работать как ты просишь — должен использоваться INDEX SEEK, и стоп на первой же записи.
На "Column2" есть некластерный индекс. Но "стоп" на первой записи не происходит. Т.е. на плане выполнения запроса я вижу большое число у параметра 'Estimated subtree cost'.
Здравствуйте, Ellin, Вы писали:
P>>Убрал top 1. P>>Как же так? А почему тогда на плане запроса не меняется значение 'Estimated I/O cost' или 'Estimated CPU cost'? P>>Что-то же должно изменяться! Время выполнения запроса не уменьшилось.
E>Оптимизатор скорее всего и так все сам убирает.
А Вам приходилось оптимизировать работу AWE? В частности, управлять буферами на основе технологии NUMA?
ppvrt пишет:
> Суть запроса — найти хоть одну строку, в которой значение в ячейке имеет > искомое значение. > Так вот, Top 1 сначала находит все строки, удовлетворяющие условию > поиска, а потом усекает результаты запроса и выводит клиенту первую > строку из результата запроса.
Так убери TOP 1 нахрен, зачем он там тебе ? Он же в EXISTS стоит.
Сервер и так знает, что тебе нужно знать только факт наличия хотя бы
одной записи.
if exists (select 1 from Table1 where Column2 = @value)
P>Убрал top 1. P>Как же так? А почему тогда на плане запроса не меняется значение 'Estimated I/O cost' или 'Estimated CPU cost'? P>Что-то же должно изменяться! Время выполнения запроса не уменьшилось.
Включи set showplan_text on, план скинь сюда, не забыв его поместить между тегами [code].
Здравствуйте, _d_m_, Вы писали:
___>Попробуй так: ___>
___>if exists (select 1 from Table1 where Column2 = @value)
___>
P>>Убрал top 1. P>>Как же так? А почему тогда на плане запроса не меняется значение 'Estimated I/O cost' или 'Estimated CPU cost'? P>>Что-то же должно изменяться! Время выполнения запроса не уменьшилось.
___>Включи set showplan_text on, план скинь сюда, не забыв его поместить между тегами.
Скрипт для создания тестовой таблицы.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[tblExample](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ParentId] [int] NULL,
CONSTRAINT [PK_tblExample] 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
ALTER TABLE [dbo].[tblExample] WITH CHECK ADD CONSTRAINT [FK_tblExample_tblExample1] FOREIGN KEY([ParentId])
REFERENCES [dbo].[tblExample] ([Id])
GO
ALTER TABLE [dbo].[tblExample] CHECK CONSTRAINT [FK_tblExample_tblExample1]
GO
Запускаем запрос вида
if exists (select 1 from tblExample
where ParentId is null)
print 'Ok'
else
print 'error'
Как видно из плана выполнения, присутствует попытка поиска строк путём запуска вложенных циклов (nested loops). А это — очень и очень хреново. Как же так?
ppvrt пишет:
> Запускаем запрос вида > > if exists (select 1 from tblExample > where ParentId is null) > print 'Ok' > else > print 'error' > > > > И получаем следующий план выполнения: > > |--Compute Scalar(DEFINE[Expr1004]=CASE WHEN [Expr1005] THEN (1) ELSE (0) END)) > |--Nested Loops(Left Semi Join, DEFINE[Expr1005] = [PROBE VALUE])) > |--Constant Scan > |--Index Seek(OBJECT[saad_test2].[dbo].[tblExample].[IX_tblExample]), SEEK[saad_test2].[dbo].[tblExample].[ParentId]=NULL) ORDERED FORWARD) > > > > Как видно из плана выполнения, присутствует попытка поиска строк путём > запуска вложенных циклов (nested loops). А это — очень и очень хреново.
Кто тебе это сказал ?
Ничего хренового нет, это раз.
во-вторых, эта записть означает, что применяется алгоритм Nested Loops для
нижеследующих таблиц, и таблица эта -- одна -- tblExample. Так что фактически
никакого Nested Loops-а нет. И план хороший, по константе по индексу
ищет одну запись.
P>Как видно из плана выполнения, присутствует попытка поиска строк путём запуска вложенных циклов (nested loops). А это — очень и очень хреново. Как же так?
Разбираем план. Index seek — нашли записи с [ParentId]=NULL. Constant Scan — подставили 1 в выборку того, что вернул index seek. nested loops — проверили наличие записей вообще.
В использовании Nested Loops ничего криминального не вижу. Интересно было бы посмотреть на большой таблице, сколько строк возвращает index seek — это видно при включенном отображении плане запроса в студии(и не предполагаемого, а реального).
Шурыгин Сергей
"Не следует преумножать сущности сверх необходимости" (с) Оккам
P>>Как видно из плана выполнения, присутствует попытка поиска строк путём запуска вложенных циклов (nested loops). А это — очень и очень хреново. Как же так?
S>Разбираем план. Index seek — нашли записи с [ParentId]=NULL. Constant Scan — подставили 1 в выборку того, что вернул index seek. nested loops — проверили наличие записей вообще.
S>В использовании Nested Loops ничего криминального не вижу. Интересно было бы посмотреть на большой таблице, сколько строк возвращает index seek — это видно при включенном отображении плане запроса в студии(и не предполагаемого, а реального).
Как-то я в итакой солянке плохо разбираюсь Возьмите а) реальную таблицу с большим количеством данных и б) реальный графический план запроса в SSMS (или EM). Тогда, если вы наведете мышь на стрелочку, соединяющую index seek c nested loops, то там будет написано число 'actual row count'. Вот если там 1 — то все нормально. Я проверял, у меня был 1. А если просто по индексу данные доставать, то и запрос выполнялся дольше и значение было соответствующее
Шурыгин Сергей
"Не следует преумножать сущности сверх необходимости" (с) Оккам