Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Нужна-ли универсальна процедура? Или можно это как-то побороть?  [new]
SandalTree
Member

Откуда: Перехлёсток восьми батог
Сообщений: 28146
Создаём 3 таблички и заполняем их:
USE TempDB
GO
CREATE TABLE A(Record_ID int IDENTITY(1,1) NOT NULL, AValue char(10) NOT NULL,
  CONSTRAINT PK_A PRIMARY KEY CLUSTERED (Record_ID ASC)) 
CREATE NONCLUSTERED INDEX IDX_A ON A ([AValue] ASC)
GO
CREATE TABLE B(Record_ID int IDENTITY(1,1) NOT NULL, BValue char(10) NOT NULL, A_ID int NOT NULL,
 CONSTRAINT PK_B PRIMARY KEY CLUSTERED (Record_ID ASC))
CREATE NONCLUSTERED INDEX IDX_B ON B (BValue ASC)
GO
CREATE TABLE C(Record_ID int IDENTITY(1,1) NOT NULL, CValue char(10) NOT NULL, B_ID int NOT NULL,
 CONSTRAINT PK_C PRIMARY KEY CLUSTERED (Record_ID ASC))
CREATE NONCLUSTERED INDEX IDX_C ON C(CValue ASC)
GO
ALTER TABLE B WITH CHECK ADD CONSTRAINT FK_B_A FOREIGN KEY(A_ID) REFERENCES A (Record_ID)
GO
ALTER TABLE B CHECK CONSTRAINT FK_B_A
GO
ALTER TABLE C  WITH CHECK ADD  CONSTRAINT FK_C_B FOREIGN KEY(B_ID) REFERENCES B(Record_ID)
GO
ALTER TABLE C CHECK CONSTRAINT FK_C_B
GO
INSERT INTO A(AValue) 
SELECT DISTINCT RIGHT(RTRIM(description),10) FROM master..sysmessages
GO
INSERT INTO B(BValue, A_ID) 
SELECT LEFT(description,10), MIN(A.Record_ID) FROM master..sysmessages s
INNER JOIN A on AValue = RIGHT(description,10)
GROUP BY LEFT(description,10)
GO
INSERT INTO C(CValue, B_ID) 
SELECT SUBSTRING(description,10,10), MIN(B.Record_ID) FROM master..sysmessages s
INNER JOIN B on BValue = LEFT(description,10)
GROUP BY SUBSTRING(description,10,10)
GO

Создаём универсальную процедуру по выемке значений:
CREATE PROC ABC
@A char(10)=Null,
@B char(10)=Null,
@C char(10)=Null
AS 
SET NOCOUNT ON
SELECT TOP 1 * 
FROM A 
INNER JOIN B on A.Record_ID = B.A_ID
INNER JOIN C on B.Record_ID = C.B_ID
WHERE (@A is null or @A = A.AValue) and 
      (@B is null or @B = B.BValue) and 
      (@C is null or @C = C.CValue)


Запускаем скрипт:
SET STATISTICS TIME ON
GO
EXEC ABC @A = ' DATABASE.'
GO
EXEC ABC @B = 'File ONLIN'
GO
EXEC ABC @C = ' open SQL '
GO
EXEC ABC @A = ' to 90RTM.'
GO

Получаем следующий результат:

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
Record_ID   AValue     Record_ID   BValue     A_ID        Record_ID   CValue     B_ID
----------- ---------- ----------- ---------- ----------- ----------- ---------- -----------
154703       DATABASE. 715678      If the qua 154703      2218644     alified ob 715678

 SQL Server Execution Times:
   CPU time = 16 ms,  elapsed time = 16 ms.


Record_ID   AValue     Record_ID   BValue     A_ID        Record_ID   CValue     B_ID
----------- ---------- ----------- ---------- ----------- ----------- ---------- -----------
154703       DATABASE. 717920      File ONLIN 154703      2215845     NE/OFFLINE 717920

 SQL Server Execution Times:
   CPU time = 55942 ms,  elapsed time = 56280 ms.


Record_ID   AValue     Record_ID   BValue     A_ID        Record_ID   CValue     B_ID
----------- ---------- ----------- ---------- ----------- ----------- ---------- -----------
145349      in access. 724242      Unable to  145349      2213384      open SQL  724242

 SQL Server Execution Times:
   CPU time = 2028 ms,  elapsed time = 2033 ms.

Record_ID   AValue     Record_ID   BValue     A_ID        Record_ID   CValue     B_ID
----------- ---------- ----------- ---------- ----------- ----------- ---------- -----------
146438       to 90RTM. 717716      Cannot spe 146438      2204226     ecify algo 717716


 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 2 ms.


Сбрасываем кэш:
DBCC FREEPROCCACHE WITH NO_INFOMSGS;


Запускаем другой скрипт:
EXEC ABC @B = 'Warning: T'
GO
EXEC ABC @C = ' open SQL '
GO
EXEC ABC @A = ' to 90RTM.'
GO
EXEC ABC @B = 'File ONLIN'

Получаем следующий результат:
 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
Record_ID   AValue     Record_ID   BValue     A_ID        Record_ID   CValue     B_ID
----------- ---------- ----------- ---------- ----------- ----------- ---------- -----------
146288       using %s. 723945      Warning: T 146288      2206267     The heap " 723945

 SQL Server Execution Times:
   CPU time = 16 ms,  elapsed time = 22 ms.

Record_ID   AValue     Record_ID   BValue     A_ID        Record_ID   CValue     B_ID
----------- ---------- ----------- ---------- ----------- ----------- ---------- -----------
145349      in access. 724242      Unable to  145349      2213384      open SQL  724242

 SQL Server Execution Times:
   CPU time = 42104 ms,  elapsed time = 42701 ms.

Record_ID   AValue     Record_ID   BValue     A_ID        Record_ID   CValue     B_ID
----------- ---------- ----------- ---------- ----------- ----------- ---------- -----------
146438       to 90RTM. 726269      Cannot add 146438      2204420     d a sparse 726269

 SQL Server Execution Times:
   CPU time = 16 ms,  elapsed time = 16 ms.

Record_ID   AValue     Record_ID   BValue     A_ID        Record_ID   CValue     B_ID
----------- ---------- ----------- ---------- ----------- ----------- ---------- -----------
154703       DATABASE. 717920      File ONLIN 154703      2215845     NE/OFFLINE 717920

 SQL Server Execution Times:
   CPU time = 16 ms,  elapsed time = 6 ms.


Совершенно очевидно что сервер кеширует процедуру по разному в зависимости он первого запускного параметра.

Кто-нибудь знает как его заставить использовать разный кеш в зависимости от используемого параметра?
26 мар 12, 22:50    [12317670]     Ответить | Цитировать Сообщить модератору
 Re: Нужна-ли универсальна процедура? Или можно это как-то побороть?  [new]
Гавриленко Сергей Алексеевич
Member

Откуда:
Сообщений: 37254
SandalTree
Совершенно очевидно что сервер кеширует процедуру по разному в зависимости он первого запускного параметра.
А планы где?

SandalTree
Кто-нибудь знает как его заставить использовать разный кеш в зависимости от используемого параметра?
option ( recompile )
26 мар 12, 23:14    [12317721]     Ответить | Цитировать Сообщить модератору
 Re: Нужна-ли универсальна процедура? Или можно это как-то побороть?  [new]
invm
Member

Откуда: Москва
Сообщений: 9845
SandalTree
Совершенно очевидно что сервер кеширует процедуру по разному в зависимости он первого запускного параметра.

Кто-нибудь знает как его заставить использовать разный кеш в зависимости от используемого параметра?
Кешируются планы выполнения, а не процедуры. А т.к. сами планы вы не привели, то можно только гадать разные они или одинаковые.

Если хотите новый план при каждом вызове, добавьте к запросу option(recompile).
26 мар 12, 23:21    [12317734]     Ответить | Цитировать Сообщить модератору
 Re: Нужна-ли универсальна процедура? Или можно это как-то побороть?  [new]
SandalTree
Member

Откуда: Перехлёсток восьми батог
Сообщений: 28146
Естественно что после сброса кэша и использования другого параметра план создаётся совсем другой.
В этом-то вся и проблема.

SELECT TOP 1 *   FROM A   INNER JOIN B on A.Record_ID = B.A_ID  INNER JOIN C on B.Record_ID = C.B_ID  WHERE (@A is null or @A = A.AValue) and         (@B is null or @B = B.BValue) and         (@C is null or @C = C.CValue)
  |--Top(TOP EXPRESSION:((1)))
       |--Nested Loops(Inner Join, WHERE:([TestDB].[dbo].[B].[Record_ID]=[TestDB].[dbo].[C].[B_ID]))
            |--Nested Loops(Inner Join, WHERE:([TestDB].[dbo].[A].[Record_ID]=[TestDB].[dbo].[B].[A_ID]))
            |    |--Index Scan(OBJECT:([TestDB].[dbo].[A].[IDX_A]),  WHERE:([@A] IS NULL OR [@A]=[TestDB].[dbo].[A].[AValue]))
            |    |--Clustered Index Scan(OBJECT:([TestDB].[dbo].[B].[PK_B]), WHERE:([@B] IS NULL OR [@B]=[TestDB].[dbo].[B].[BValue]))
            |--Clustered Index Scan(OBJECT:([TestDB].[dbo].[C].[PK_C]), WHERE:([@C] IS NULL OR [@C]=[TestDB].[dbo].[C].[CValue]))


SELECT TOP 1 *   FROM A   INNER JOIN B on A.Record_ID = B.A_ID  INNER JOIN C on B.Record_ID = C.B_ID  WHERE (@A is null or @A = A.AValue) and         (@B is null or @B = B.BValue) and         (@C is null or @C = C.CValue)
  |--Top(TOP EXPRESSION:((1)))
       |--Nested Loops(Inner Join, WHERE:([TestDB].[dbo].[B].[Record_ID]=[TestDB].[dbo].[C].[B_ID]))
            |--Nested Loops(Inner Join, OUTER REFERENCES:([TestDB].[dbo].[B].[A_ID]))
            |    |--Nested Loops(Inner Join, OUTER REFERENCES:([TestDB].[dbo].[B].[Record_ID]))
            |    |    |--Index Scan(OBJECT:([TestDB].[dbo].[B].[IDX_B]),  WHERE:([@B] IS NULL OR [@B]=[TestDB].[dbo].[B].[BValue]))
            |    |    |--Clustered Index Seek(OBJECT:([TestDB].[dbo].[B].[PK_B]), SEEK:([TestDB].[dbo].[B].[Record_ID]=[TestDB].[dbo].[B].[Record_ID]) LOOKUP ORDERED FORWARD)
            |    |--Clustered Index Seek(OBJECT:([TestDB].[dbo].[A].[PK_A]), SEEK:([TestDB].[dbo].[A].[Record_ID]=[TestDB].[dbo].[B].[A_ID]),  WHERE:([@A] IS NULL OR [@A]=[TestDB].[dbo].[A].[AValue]) ORDERED FORWARD)
            |--Clustered Index Scan(OBJECT:([TestDB].[dbo].[C].[PK_C]), WHERE:([@C] IS NULL OR [@C]=[TestDB].[dbo].[C].[CValue]))

SELECT TOP 1 *   FROM A   INNER JOIN B on A.Record_ID = B.A_ID  INNER JOIN C on B.Record_ID = C.B_ID  WHERE (@A is null or @A = A.AValue) and         (@B is null or @B = B.BValue) and         (@C is null or @C = C.CValue)
  |--Top(TOP EXPRESSION:((1)))
       |--Nested Loops(Inner Join, OUTER REFERENCES:([TestDB].[dbo].[B].[A_ID]))
            |--Nested Loops(Inner Join, OUTER REFERENCES:([TestDB].[dbo].[C].[B_ID]))
            |    |--Nested Loops(Inner Join, OUTER REFERENCES:([TestDB].[dbo].[C].[Record_ID]))
            |    |    |--Index Scan(OBJECT:([TestDB].[dbo].[C].[IDX_C]),  WHERE:([@C] IS NULL OR [@C]=[TestDB].[dbo].[C].[CValue]))
            |    |    |--Clustered Index Seek(OBJECT:([TestDB].[dbo].[C].[PK_C]), SEEK:([TestDB].[dbo].[C].[Record_ID]=[TestDB].[dbo].[C].[Record_ID]) LOOKUP ORDERED FORWARD)
            |    |--Clustered Index Seek(OBJECT:([TestDB].[dbo].[B].[PK_B]), SEEK:([TestDB].[dbo].[B].[Record_ID]=[TestDB].[dbo].[C].[B_ID]),  WHERE:([@B] IS NULL OR [@B]=[TestDB].[dbo].[B].[BValue]) ORDERED FORWARD)
            |--Clustered Index Seek(OBJECT:([TestDB].[dbo].[A].[PK_A]), SEEK:([TestDB].[dbo].[A].[Record_ID]=[TestDB].[dbo].[B].[A_ID]),  WHERE:([@A] IS NULL OR [@A]=[TestDB].[dbo].[A].[AValue]) ORDERED FORWARD)
27 мар 12, 00:19    [12317822]     Ответить | Цитировать Сообщить модератору
 Re: Нужна-ли универсальна процедура? Или можно это как-то побороть?  [new]
SandalTree
Member

Откуда: Перехлёсток восьми батог
Сообщений: 28146
В данном конкретном примере проблема решается достаточно просто использованием промежуточных переменных:
ALTER PROC ABC
@A char(10)=Null,
@B char(10)=Null,
@C char(10)=Null
AS 
SET NOCOUNT ON

DECLARE @A1 char(10), @B1 char(10), @C1 char(10)
SELECT @A1 = @A, @B1 = @B, @C1 = @C

SELECT TOP 1 * 
FROM A 
INNER JOIN B on A.Record_ID = B.A_ID
INNER JOIN C on B.Record_ID = C.B_ID
WHERE (@A1 is null or @A1 = A.AValue) and 
      (@B1 is null or @B1 = B.BValue) and 
      (@C1 is null or @C1 = C.CValue)


SELECT TOP 1 *   FROM A   INNER JOIN B on A.Record_ID = B.A_ID  INNER JOIN C on B.Record_ID = C.B_ID  WHERE (@A1 is null or @A1 = A.AValue) and         (@B1 is null or @B1 = B.BValue) and         (@C1 is null or @C1 = C.CValue)
  |--Top(TOP EXPRESSION:((1)))
       |--Nested Loops(Inner Join, OUTER REFERENCES:([TestDB].[dbo].[B].[A_ID], [Expr1013]) WITH UNORDERED PREFETCH)
            |--Nested Loops(Inner Join, OUTER REFERENCES:([TestDB].[dbo].[C].[B_ID], [Expr1012]) WITH UNORDERED PREFETCH)
            |    |--Clustered Index Scan(OBJECT:([TestDB].[dbo].[C].[PK_C]), WHERE:([@C1] IS NULL OR [@C1]=[TestDB].[dbo].[C].[CValue]))
            |    |--Clustered Index Seek(OBJECT:([TestDB].[dbo].[B].[PK_B]), SEEK:([TestDB].[dbo].[B].[Record_ID]=[TestDB].[dbo].[C].[B_ID]),  WHERE:([@B1] IS NULL OR [@B1]=[TestDB].[dbo].[B].[BValue]) ORDERED FORWARD)
            |--Clustered Index Seek(OBJECT:([TestDB].[dbo].[A].[PK_A]), SEEK:([TestDB].[dbo].[A].[Record_ID]=[TestDB].[dbo].[B].[A_ID]),  WHERE:([@A1] IS NULL OR [@A1]=[TestDB].[dbo].[A].[AValue]) ORDERED FORWARD)


Однако в моём конкретном случае это проблемы не решает.
Рекомпиляция не подходит, ибо это ничем не лучше чем использование динамических запросов, чего в данном случае и пытаюсь избежать.

Ещё идеи будут?
27 мар 12, 00:24    [12317834]     Ответить | Цитировать Сообщить модератору
 Re: Нужна-ли универсальна процедура? Или можно это как-то побороть?  [new]
Гавриленко Сергей Алексеевич
Member

Откуда:
Сообщений: 37254
SandalTree
Рекомпиляция не подходит, ибо это ничем не лучше чем использование динамических запросов, чего в данном случае и пытаюсь избежать.
Гораздо лучше. Ни прав прямых на таблицу не надо, ни от injection защищаться.
SandalTree
Ещё идеи будут?
У вас есть три опции:
  • пользоваться кешированным планами, т.е. то, с чего вы начали;
  • зафиксировать какой-то план для общего случая, т.е. то, что вы сделали;
  • стоить план для конкретного значения переменных; т.е. рекомпиляция.
  • 27 мар 12, 00:38    [12317851]     Ответить | Цитировать Сообщить модератору
     Re: Нужна-ли универсальна процедура? Или можно это как-то побороть?  [new]
    SandalTree
    Member

    Откуда: Перехлёсток восьми батог
    Сообщений: 28146
    Гавриленко Сергей Алексеевич
    SandalTree
    Рекомпиляция не подходит, ибо это ничем не лучше чем использование динамических запросов, чего в данном случае и пытаюсь избежать.
    Гораздо лучше. Ни прав прямых на таблицу не надо, ни от injection защищаться.
    SandalTree
    Ещё идеи будут?
    У вас есть три опции:
  • пользоваться кешированным планами, т.е. то, с чего вы начали;
  • зафиксировать какой-то план для общего случая, т.е. то, что вы сделали;
  • стоить план для конкретного значения переменных; т.е. рекомпиляция.
  • Проблему поборол использованием 2х запросов.

    Что-то типа:
    ALTER PROC ABC
    @A char(10)=Null,
    @B char(10)=Null,
    @C char(10)=Null
    AS 
    SET NOCOUNT ON
    
    DECLARE @B1 char(10), @C1 char(10)
    SELECT @B1 = @B, @C1 = @C
    
    IF @A is not null
      SELECT TOP 1 * 
      FROM A 
      INNER JOIN B on A.Record_ID = B.A_ID
      INNER JOIN C on B.Record_ID = C.B_ID
      WHERE @A1 = A.AValue
    ELSE
      SELECT TOP 1 * 
      FROM A 
      INNER JOIN B on A.Record_ID = B.A_ID
      INNER JOIN C on B.Record_ID = C.B_ID
      WHERE 
            (@B1 is null or @B1 = B.BValue) and 
            (@C1 is null or @C1 = C.CValue)
    

    Так получил хороший перформанс для одного критического параметра и для всех остальных.
    Скуль строит два плана для двух разных запросов.

    Метод тупее не придумаешь, но работает.
    27 мар 12, 01:44    [12317914]     Ответить | Цитировать Сообщить модератору
     Re: Нужна-ли универсальна процедура? Или можно это как-то побороть?  [new]
    Mind
    Member

    Откуда: Лучший город на Земле
    Сообщений: 2322
    SandalTree
    В данном конкретном примере проблема решается достаточно просто использованием промежуточных переменных:
    Вместо хака с локальными переменными можно пользоваться вполне документированной опцией OPTIMIZE FOR UNKNOWN

    SandalTree
    Рекомпиляция не подходит, ибо это ничем не лучше чем использование динамических запросов, чего в данном случае и пытаюсь избежать.
    Вы путаете теплое с мягким.
    27 мар 12, 02:57    [12317935]     Ответить | Цитировать Сообщить модератору
     Re: Нужна-ли универсальна процедура? Или можно это как-то побороть?  [new]
    SandalTree
    Member

    Откуда: Перехлёсток восьми батог
    Сообщений: 28146
    Mind
    SandalTree
    В данном конкретном примере проблема решается достаточно просто использованием промежуточных переменных:
    Вместо хака с локальными переменными можно пользоваться вполне документированной опцией OPTIMIZE FOR UNKNOWN

    SandalTree
    Рекомпиляция не подходит, ибо это ничем не лучше чем использование динамических запросов, чего в данном случае и пытаюсь избежать.
    Вы путаете теплое с мягким.


    За "OPTIMIZE FOR UNKNOWN" спасибо, а вот рекомпиляция работает в 2-7 раз медленнее динамических запросов.
    27 мар 12, 21:05    [12323717]     Ответить | Цитировать Сообщить модератору
     Re: Нужна-ли универсальна процедура? Или можно это как-то побороть?  [new]
    Mind
    Member

    Откуда: Лучший город на Земле
    Сообщений: 2322
    SandalTree
    Mind
    пропущено...
    Вместо хака с локальными переменными можно пользоваться вполне документированной опцией OPTIMIZE FOR UNKNOWN

    пропущено...
    Вы путаете теплое с мягким.


    рекомпиляция работает в 2-7 раз медленнее динамических запросов.

    Как насчет доказательства этого утверждения? Динамические запросы что ли не компилируются?
    Или хотя бы кларификации, что значит в 2-7 раз медленне? Компиляция? Или весь запрос?  Диски что-ли начинают медленнее шуршать если OPTION(RECOMPILE) включить?
    28 мар 12, 00:45    [12324366]     Ответить | Цитировать Сообщить модератору
     Re: Нужна-ли универсальна процедура? Или можно это как-то побороть?  [new]
    SandalTree
    Member

    Откуда: Перехлёсток восьми батог
    Сообщений: 28146
    Mind
    рекомпиляция работает в 2-7 раз медленнее динамических запросов.

    Как насчет доказательства этого утверждения? Динамические запросы что ли не компилируются?
    Или хотя бы кларификации, что значит в 2-7 раз медленне? Компиляция? Или весь запрос?  Диски что-ли начинают медленнее шуршать если OPTION(RECOMPILE) включить?

    CREATE PROC ABC
    @A char(10)=Null,
    @B char(10)=Null,
    @C char(10)=Null
    AS 
    SET NOCOUNT ON
    
    DECLARE @S varchar(MAX)
    SET @S = '  SELECT TOP 1 * FROM A 
      INNER JOIN B on A.Record_ID = B.A_ID
      INNER JOIN C on B.Record_ID = C.B_ID
      WHERE 1 = 1 '
    
    IF @A is not null
      SET @S = @S + ' and A.AValue = ' + '''' + @A + ''''
    IF @B is not null
      SET @S = @S + ' and B.BValue = ' + '''' + @B + ''''
    IF @C is not null
      SET @S = @S + ' and C.CValue = ' + '''' + @C + ''''
    
    EXECUTE (@S)
    

    ALTER PROC ABC
    @A char(10)=Null,
    @B char(10)=Null,
    @C char(10)=Null
    AS 
    SET NOCOUNT ON
    
    DECLARE @S nvarchar(MAX)
    SET @S = '  SELECT TOP 1 * FROM A 
      INNER JOIN B on A.Record_ID = B.A_ID
      INNER JOIN C on B.Record_ID = C.B_ID
      WHERE 1 = 1 '
    
    IF @A is not null
    BEGIN 
      SET @S = @S + ' and A.AValue = @A1'
      EXEC sp_executesql @S, N'@A1 char(10)', @A 
    END
    ELSE IF @B is not null
    BEGIN 
      SET @S = @S + ' and B.BValue = @B1'
      EXEC sp_executesql @S, N'@B1 char(10)', @B 
    END
    ELSE IF @C is not null
    BEGIN 
      SET @S = @S + ' and C.CValue = @C1'
      EXEC sp_executesql @S, N'@C1 char(10)', @C
    END
    ELSE 
      EXEC sp_executesql @SGO
    

    ALTER PROC ABC
    @A char(10)=Null,
    @B char(10)=Null,
    @C char(10)=Null
    AS 
    SET NOCOUNT ON
    
    SELECT TOP 1 * 
    FROM A 
    INNER JOIN B on A.Record_ID = B.A_ID
    INNER JOIN C on B.Record_ID = C.B_ID
    WHERE (@A is null or @A = A.AValue) and 
          (@B is null or @B = B.BValue) and 
          (@C is null or @C = C.CValue)
    OPTION (RECOMPILE);      
    

    SET STATISTICS TIME ON
    GO
    EXEC ABC @A = ' DATABASE.'
    GO
    EXEC ABC @B = 'File ONLIN'
    GO
    EXEC ABC @C = ' open SQL '
    GO
    EXEC ABC @A = ' to 90RTM.', @B = 'Warning: T', @C = 'e CLR (Com'
    GO
    EXEC ABC 
    GO
    EXEC ABC @A = ' to 90RTM.'
    GO
    EXEC ABC @B = 'Warning: T'
    GO
    


    1:
       CPU time = 15 ms,  elapsed time = 12 ms.
       CPU time = 16 ms,  elapsed time = 9 ms.
       CPU time = 15 ms,  elapsed time = 6 ms.
       CPU time = 16 ms,  elapsed time = 6 ms.
       CPU time = 0 ms,  elapsed time = 9 ms.
       CPU time = 0 ms,  elapsed time = 8 ms.
    2:
       CPU time = 0 ms,  elapsed time = 6 ms.
       CPU time = 0 ms,  elapsed time = 3 ms.
       CPU time = 0 ms,  elapsed time = 0 ms.
       CPU time = 0 ms,  elapsed time = 2 ms.
       CPU time = 0 ms,  elapsed time = 1 ms.
       CPU time = 0 ms,  elapsed time = 2 ms.
    3:
       CPU time = 31 ms,  elapsed time = 20 ms.
       CPU time = 16 ms,  elapsed time = 19 ms.
       CPU time = 0 ms,  elapsed time = 8 ms.
       CPU time = 15 ms,  elapsed time = 11 ms.
       CPU time = 16 ms,  elapsed time = 14 ms.
       CPU time = 16 ms,  elapsed time = 11 ms.
    


    Вот мои данные, хочешь, проверь на своей машине.
    28 мар 12, 01:34    [12324429]     Ответить | Цитировать Сообщить модератору
     Re: Нужна-ли универсальна процедура? Или можно это как-то побороть?  [new]
    Mind
    Member

    Откуда: Лучший город на Земле
    Сообщений: 2322
    SandalTree
    1:
       CPU time = 15 ms,  elapsed time = 12 ms.
       CPU time = 16 ms,  elapsed time = 9 ms.
       CPU time = 15 ms,  elapsed time = 6 ms.
       CPU time = 16 ms,  elapsed time = 6 ms.
       CPU time = 0 ms,  elapsed time = 9 ms.
       CPU time = 0 ms,  elapsed time = 8 ms.
    2:
       CPU time = 0 ms,  elapsed time = 6 ms.
       CPU time = 0 ms,  elapsed time = 3 ms.
       CPU time = 0 ms,  elapsed time = 0 ms.
       CPU time = 0 ms,  elapsed time = 2 ms.
       CPU time = 0 ms,  elapsed time = 1 ms.
       CPU time = 0 ms,  elapsed time = 2 ms.
    3:
       CPU time = 31 ms,  elapsed time = 20 ms.
       CPU time = 16 ms,  elapsed time = 19 ms.
       CPU time = 0 ms,  elapsed time = 8 ms.
       CPU time = 15 ms,  elapsed time = 11 ms.
       CPU time = 16 ms,  elapsed time = 14 ms.
       CPU time = 16 ms,  elapsed time = 11 ms.
    


    Вот мои данные, хочешь, проверь на своей машине.

    Могу сделать только один вывод, вариант №3 медленне варианта №2 в среднем на 11.5 мс. Никаких в 2-7 раз тут не вижу. Время компиляции в вашем примере может быть в разы больше чем время выполнения, так что вовсе не показательно. Если для вас 11.5 мс критично, например запрос дергают 100 раз в секунду (100*11.5 = 1.1 сек), тогда да, лучше отказаться от рекомпиляции каждый раз. Но если это запрос для отчета, который запускают несколько раз в день, время генерации которого скажем 3 минуты, то потерять 11.5 мс на компиляцию это не большая проблема при условии что будет построен хороший план.
    28 мар 12, 04:15    [12324513]     Ответить | Цитировать Сообщить модератору
     Re: Нужна-ли универсальна процедура? Или можно это как-то побороть?  [new]
    SandalTree
    Member

    Откуда: Перехлёсток восьми батог
    Сообщений: 28146
    Mind
    Если для вас 11.5 мс критично, например запрос дергают 100 раз в секунду (100*11.5 = 1.1 сек), тогда да, лучше отказаться от рекомпиляции каждый раз. Но если это запрос для отчета, который запускают несколько раз в день, время генерации которого скажем 3 минуты, то потерять 11.5 мс на компиляцию это не большая проблема при условии что будет построен хороший план.
    Именно этот запрос могут запускать до 50 тысяч раз в день.
    И таких запросов (самых разных) будет много много (по 50К).

    Думаю это много, поэтому хочу с самого начала найти самый оптимальный подход.
    28 мар 12, 04:58    [12324518]     Ответить | Цитировать Сообщить модератору
    Все форумы / Microsoft SQL Server Ответить