Como posso contornar SQL Server - inline Tabela Valor variação plano de execução de função com base em parâmetros?

StackOverflow https://stackoverflow.com/questions/450091

Pergunta

Aqui está a situação:
Eu tenho uma função de valor de tabela com um parâmetro de data e hora, para não dizer TDF (p_date), que os filtros de cerca de dois milhões de linhas selecionando aqueles com data de coluna menor do que p_date e calcula alguns valores agregados sobre outras colunas.
Ele funciona muito bem, mas se p_date é uma função valor escalar personalizado (retornando no final do dia no meu caso) o plano de execução é alterado um a consulta vai de 1 seg a 1 minuto de tempo de execução.

A prova da tabela conceito - 1K produtos, linhas 2M:

CREATE TABLE [dbo].[POC](
    [Date] [datetime] NOT NULL,
    [idProduct] [int] NOT NULL,
    [Quantity] [int] NOT NULL
) ON [PRIMARY]

A função de valor de tabela em linha:

CREATE FUNCTION tdf (@p_date datetime)
RETURNS TABLE 
AS
RETURN 
(
    SELECT idProduct, SUM(Quantity) AS TotalQuantity,
         max(Date) as LastDate
    FROM POC
    WHERE (Date < @p_date)
    GROUP BY idProduct
)

A função de valor escalar:

CREATE FUNCTION [dbo].[EndOfDay] (@date datetime)
RETURNS datetime
AS
BEGIN
    DECLARE @res datetime
    SET @res=dateadd(second, -1,
         dateadd(day, 1, 
             dateadd(ms, -datepart(ms, @date),
                 dateadd(ss, -datepart(ss, @date),
                    dateadd(mi,- datepart(mi,@date),
                         dateadd(hh, -datepart(hh, @date), @date))))))
    RETURN @res
END

Consulta 1 - grande de Trabalho

SELECT * FROM [dbo].[tdf] (getdate())

O fim do plano de execução: Custo fluxo agregado de 13%

Consulta 2 - Não é tão grande

SELECT * FROM [dbo].[tdf] (dbo.EndOfDay(getdate()))

O fim do plano de execução: Custo fluxo agregado de 4% <--- Custo Filtro 12%

Foi útil?

Solução

A sobrecarga é a sua função escalar.

O TVF aqui é expandido como uma macro in-line de modo

SELECT * FROM [dbo].[tdf] (getdate())

se torna

SELECT     idProduct, SUM(Quantity) AS TotalQuantity, max(Date) as LastDate
    FROM         POC
    WHERE     Date < getdate()
    GROUP BY idProduct

Quando você usa final de função dia escalar, SQL não pode avaliar a EOD (GETDATE ()) como uma constante. Não consigo encontrar meu artigo rapidamente sobre como SQL avalia este material, desculpe.

Eu acho que ele está sendo avaliada para cada linha, e não adiantado como você quer.

Eu Calulate a declaração EOD separadamente:

DECLARE @eod datetime;
SET @eod = dbo.EndOfDay(getdate());
SELECT * FROM [dbo].[tdf] (@eod)

Eu também usar este para a função de EOD:

DATEADD(second, -1, DATEADD(day, 1, (DATEDIFF(day, 0, @date))))

EDIT: Outra pergunta que eu respondeu

Outras dicas

Você pode reescrever EndOfDay como um inline UDF também, e usar UDFs em linha aninhados. Exemplos:

Muitos UDFs em linha aninhados são muito rápidos

Cálculo terceira quarta-feira do mês, com linha UDFs

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top