Sql server 临时表与表变量

Sql server 临时表与表变量,sql-server,Sql Server,我必须编写一个表函数,因此我在SQL Server中原型化了查询,并使用了一个临时表,但当我将其更改为表变量时,查询将从大约1分钟变为2小时以上 第二个代码是: DECLARE @DETALLE TABLE ( FECHA smalldatetime, NO_OP NVARCHAR(100), MONTO FLOAT, PLAZO INT, CLIENTE NVARCHAR(100) ) -- CALCULO EL PLAZO POR EL MONTO,

我必须编写一个表函数,因此我在SQL Server中原型化了查询,并使用了一个临时表,但当我将其更改为表变量时,查询将从大约1分钟变为2小时以上

第二个代码是:

DECLARE @DETALLE TABLE
(
    FECHA smalldatetime,
    NO_OP NVARCHAR(100),
    MONTO FLOAT,
    PLAZO INT,
    CLIENTE NVARCHAR(100)
)

-- CALCULO EL PLAZO POR EL MONTO, EL CUAL SERA EL NUMERADOR --
--DROP TABLE #DETALLE
INSERT INTO @DETALLE
    SELECT 
        D.FECHA, D.NO_OP,
        MONTO = (D.CAPITAL+D.INTERESES)/1000000,
        PLAZO = CAST(D.FECHA_VCTO-D.FECHA AS INT),
        CLIENTE = CASE 
                     WHEN MIN_MAY = 'N' THEN 'MINORISTA'
                     WHEN M.ORIGEN = 'MESA LIQUIDEZ' THEN 'CLIENTE LIQUIDEZ'
                     WHEN M.ORIGEN IS NULL AND MIN_MAY = 'S' AND COD_SUCURSAL = '246' THEN 'EMPRESAS SALES'
                     ELSE 'OTRO MAYORISTA' 
                  END
    --INTO #DETALLE
    FROM 
        BCI_RIF_ODS.dbo.Tab_Detalle_DAP AS D 
    INNER JOIN 
        BCI_RI_ODS.dbo.Cliente_Traduce AS C ON (C.CLIENTE_ID = D.CLIENTE_ID)
    LEFT JOIN 
        BCI_RIF_ODS.dbo.TabMae_CliMesa AS M ON (D.CLIENTE_ID = M.CLIENTE_ID)
    WHERE 
        FECHA >= '20180101' AND FECHA_VCTO > FECHA

SELECT 
    D1.CLIENTE, D1.FECHA,
    NUMERADOR = SUM(D1.PLAZO*D1.MONTO),
    MONTO = D2.MONTO,
    FACTOR = SUM(D1.PLAZO*D1.MONTO)/D2.Monto
FROM
    @DETALLE D1 
LEFT JOIN
    (SELECT 
         CLIENTE, FECHA,
         MONTO = SUM(MONTO)
     FROM 
         @DETALLE
     GROUP BY 
         CLIENTE, FECHA) D2 ON (D1.CLIENTE = D2.CLIENTE AND D1.Fecha = D2.Fecha)
GROUP BY 
    D1.CLIENTE, D1.Fecha, D2.MONTO

您真的不需要为数据创建另一个副本,然后只需执行聚合即可。您可以在这里使用cte。类似的操作可能比将数据从一个表复制到一个变量要好得多

with DETALLE as
(
    -- CALCULO EL PLAZO POR EL MONTO, EL CUAL SERA EL NUMERADOR --
    SELECT 
        D.FECHA, D.NO_OP,
        MONTO = (D.CAPITAL+D.INTERESES)/1000000,
        PLAZO = CAST(D.FECHA_VCTO-D.FECHA AS INT),
        CLIENTE = CASE 
                        WHEN MIN_MAY = 'N' THEN 'MINORISTA'
                        WHEN M.ORIGEN = 'MESA LIQUIDEZ' THEN 'CLIENTE LIQUIDEZ'
                        WHEN M.ORIGEN IS NULL AND MIN_MAY = 'S' AND COD_SUCURSAL = '246' THEN 'EMPRESAS SALES'
                        ELSE 'OTRO MAYORISTA' 
                    END
    FROM 
        BCI_RIF_ODS.dbo.Tab_Detalle_DAP AS D 
    INNER JOIN 
        BCI_RI_ODS.dbo.Cliente_Traduce AS C ON (C.CLIENTE_ID = D.CLIENTE_ID)
    LEFT JOIN 
        BCI_RIF_ODS.dbo.TabMae_CliMesa AS M ON (D.CLIENTE_ID = M.CLIENTE_ID)
    WHERE 
        FECHA >= '20180101' AND FECHA_VCTO > FECHA
)

SELECT 
    D1.CLIENTE, D1.FECHA,
    NUMERADOR = SUM(D1.PLAZO*D1.MONTO),
    MONTO = D2.MONTO,
    FACTOR = SUM(D1.PLAZO*D1.MONTO)/D2.Monto
FROM
    DETALLE D1 
LEFT JOIN
    (SELECT 
         CLIENTE, FECHA,
         MONTO = SUM(MONTO)
     FROM 
         DETALLE
     GROUP BY 
         CLIENTE, FECHA) D2 ON (D1.CLIENTE = D2.CLIENTE AND D1.Fecha = D2.Fecha)
GROUP BY 
    D1.CLIENTE, D1.Fecha, D2.MONTO

表变量中插入了多少行?一般来说,表变量对于几十行以上的数据都不是最优的。IMHO,这取决于您要存储的数据量……如果数据量很小,您可以使用表变量而不会出现问题,但是如果您使用的数据量相当大,您应该使用临时表,因为,使用临时表,您可以更好地利用sql server,如Statiststics和优化器。@Hackerman这是一个很大的集合,但我正在尝试构建一个表值函数,因此使用临时表的选择是不现实的,我还有其他选择吗?@SeanLange源代码会很有用,因为我还没有找到任何关于表值函数的信息。如果您试图实现表值函数,为什么要首先使用临时表或表变量?这表明函数中有多个select语句,这意味着它是一个多语句表值函数,并且这些语句的性能通常甚至比标量函数还要差。也许我们在这里需要做的是帮助您构建一个高效的内联表值函数,它根本不需要临时表或变量。我得到一个错误:函数中包含的Select语句无法将数据返回到客户端。那么,也许您可以共享您的代码?显然,您正试图将其用作函数体?我在这里帮助处于极端劣势的人,并在黑暗中编码。@eduardo0请花些时间学习两种表值函数TVP。最简单的形式是内联TVP,它最适合Sean给您的查询。将其与您可能使用的表单(即多语句TVP)进行对比。在这种形式下,您可以在函数声明中定义表并填充它,即在函数逻辑中插入到表中。