Долгое выполнение простейшего цикла

Pmick
Дата: 21.02.2010 13:43:55
Добрый день.
set nocount on;
declare @n char(13)
declare @a datetime

select @n = min(n) from b(nolock)
while @n is not null begin

select @a = min(a) from b(nolock) where n = @n
while @a is not null begin
select @a = min(a) from b(nolock) where n = @n and a > @a
end
select @n = min(n) from b(nolock) where n > @n
end

Microsoft SQL Server 2005 - 9.00.4035.00 (Intel X86) Nov 24 2008 13:01:59 Copyright (c) 1988-2005 Microsoft Corporation Enterprise Evaluation Edition on Windows NT 6.0 (Build 6001: Service Pack 1)

записей - 1136474
При запросе через локальную сеть - 23 секунды, через WEB - конца не видно!!
Может кто знает ответ наизусть? Заранее благодарен
Mnior
Дата: 21.02.2010 13:54:47
Долой роботов. Им не место среди людей.
Убей в себе процедурное мышление.

WAITFOR DELAY '00:00:23'
stimpi
Дата: 21.02.2010 14:25:35
уверен что это можно было переписать более нормально без N пробегов по миллионной таблице.
так же непонятно как вы вызываете этот кусок t-sql и планы выполнения.
весь код в студию с планами.
iap
Дата: 21.02.2010 14:33:29
Mnior
Долой роботов. Им не место среди людей.
Убей в себе процедурное мышление.

WAITFOR DELAY '00:00:23'
По-моему, мы имеем дело не с дурным мышлением, а с дурным в квадрате.
Миллион раз вычислять минимум - каково!
Даже простой курсор в порядке возрастания b.a был бы в миллиард раз быстрее...
Pmick
Дата: 21.02.2010 14:52:58
stimpi,

SET SHOWPLAN_TEXT ON
SET NOCOUNT ON;

DECLARE @NLS CHAR(13)
DECLARE @ACDATE DATETIME

SELECT @NLS = MIN(NLS) FROM ARAS
WHILE @NLS IS NOT NULL BEGIN
	SELECT @ACDATE = MIN(ACDATE) FROM ARAS WHERE NLS = @NLS
	WHILE @ACDATE IS NOT NULL BEGIN
		SELECT @ACDATE = MIN(ACDATE) FROM ARAS WHERE NLS = @NLS AND ACDATE > @ACDATE 
	END
	SELECT @NLS = MIN(NLS) FROM ARAS WHERE NLS > @NLS
END

DECLARE @NLS CHAR(13) DECLARE @ACDATE DATETIME SELECT @NLS = MIN(NLS) FROM ARAS(NOLOCK)

|--Compute Scalar(DEFINE:([Expr1004]=CONVERT_IMPLICIT(char(13),[Expr1003],0)))
|--Stream Aggregate(DEFINE:([Expr1003]=MIN([Kvplata].[dbo].[Aras].[NLS])))
|--Top(TOP EXPRESSION:((1)))
|--Index Scan(OBJECT:([Kvplata].[dbo].[Aras].[Nls]), ORDERED FORWARD)

WHILE @NLS IS NOT NULL
BEGIN SELECT @ACDATE = MIN(ACDATE) FROM ARAS(NOLOCK) WHERE NLS = @NLS

|--Compute Scalar(DEFINE:([Expr1004]=CONVERT_IMPLICIT(datetime,[Expr1003],0)))
|--Stream Aggregate(DEFINE:([Expr1003]=MIN([Kvplata].[dbo].[Aras].[ACDATE])))
|--Top(TOP EXPRESSION:((1)))
|--Index Seek(OBJECT:([Kvplata].[dbo].[Aras].[Nls]), SEEK:([Kvplata].[dbo].[Aras].[NLS]=CONVERT_IMPLICIT(nchar(13),[@NLS],0)) ORDERED BACKWARD)

WHILE @ACDATE IS NOT NULL
BEGIN SELECT @ACDATE = MIN(ACDATE) FROM ARAS(NOLOCK) WHERE NLS = @NLS AND ACDATE > @ACDATE

|--Compute Scalar(DEFINE:([Expr1004]=CONVERT_IMPLICIT(datetime,[Expr1003],0)))
|--Stream Aggregate(DEFINE:([Expr1003]=MIN([Kvplata].[dbo].[Aras].[ACDATE])))
|--Top(TOP EXPRESSION:((1)))
|--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1008], [Expr1009], [Expr1007]))
|--Compute Scalar(DEFINE:(([Expr1008],[Expr1009],[Expr1007])=GetRangeWithMismatchedTypes([@ACDATE],NULL,(6))))
| |--Constant Scan
|--Index Seek(OBJECT:([Kvplata].[dbo].[Aras].[Nls]), SEEK:([Kvplata].[dbo].[Aras].[NLS]=CONVERT_IMPLICIT(nchar(13),[@NLS],0) AND [Kvplata].[dbo].[Aras].[ACDATE] < [Expr1009] AND [Kvplata].[dbo].[Aras].[ACDATE] > [Expr1008])

END SELECT @NLS = MIN(NLS) FROM ARAS(NOLOCK) WHERE NLS > @NLS

|--Compute Scalar(DEFINE:([Expr1004]=CONVERT_IMPLICIT(char(13),[Expr1003],0)))
|--Stream Aggregate(DEFINE:([Expr1003]=MIN([Kvplata].[dbo].[Aras].[NLS])))
|--Top(TOP EXPRESSION:((1)))
|--Index Seek(OBJECT:([Kvplata].[dbo].[Aras].[Nls]), SEEK:([Kvplata].[dbo].[Aras].[NLS] > CONVERT_IMPLICIT(nchar(13),[@NLS],0)) ORDERED FORWARD)

END

Со всеми постами о дурном мышлении согласен на все сто! Это пробный код, никаких задач не решающий, просто неприятно поразивший временем выполнения...
stimpi
Дата: 21.02.2010 15:27:39
на выходе будет всегда

@NLS NULL
@ACDATE NULL

вызовы из ADO.NET дописывают свои настройки (типа set nocount on;), они то и влияют на время выполнения.
автор
Different default settings in the client API and in SSMS. Next the
query runs slow in the app, run this command in SSMS first:
SET ARITHABORT OFF. ARITHABORT is one of these settings that is an
attribute of the query plan.
Pmick
Дата: 21.02.2010 15:36:35
stimpi,

Все правильно, процедура ничего не должна возвращать. Непонятно опять же следующее: если запрос ушел на сервер и там выполняется ничего не возвращая, как на это может влиять откуда и с какой скоростью приконнектился SQL Query Analyzer?
Pmick
Дата: 21.02.2010 16:08:22
iap,

DECLARE CUR CURSOR FOR SELECT A.ACDATE, A.NLS FROM   ARAS A(NOLOCK)

OPEN CUR

DECLARE @ACDATE DATETIME
DECLARE @NLS CHAR(13)

FETCH NEXT FROM CUR INTO @ACDATE, @NLS
WHILE @@FETCH_STATUS = 0
BEGIN
	FETCH NEXT FROM CUR INTO @ACDATE, @NLS
END

CLOSE CUR
DEALLOCATE CUR

время выполнения - 38 секунд, можете быстрее?
iljy
Дата: 21.02.2010 17:16:17
Pmick
iap,

DECLARE CUR CURSOR FOR SELECT A.ACDATE, A.NLS FROM   ARAS A(NOLOCK)

OPEN CUR

DECLARE @ACDATE DATETIME
DECLARE @NLS CHAR(13)

FETCH NEXT FROM CUR INTO @ACDATE, @NLS
WHILE @@FETCH_STATUS = 0
BEGIN
	FETCH NEXT FROM CUR INTO @ACDATE, @NLS
END

CLOSE CUR
DEALLOCATE CUR

время выполнения - 38 секунд, можете быстрее?

можем.
DECLARE @ACDATE DATETIME, @NLS CHAR(13)
результат будет тот же самый.
Pmick
Дата: 21.02.2010 17:45:43
iljy,

DECLARE CUR CURSOR FOR SELECT A.ACDATE, A.NLS FROM   ARAS A(NOLOCK)

OPEN CUR

DECLARE @ACDATE DATETIME
DECLARE @NLS CHAR(13)

FETCH NEXT FROM CUR INTO @ACDATE, @NLS
WHILE @@FETCH_STATUS = 0
BEGIN
	-- здесь идет тело скрипта, которое нужно выполнить...
	FETCH NEXT FROM CUR INTO @ACDATE, @NLS
END

CLOSE CUR
DEALLOCATE CUR

это тоже можете?