如何优化此 SQL Server 查询 - 多个子查询

Posted

技术标签:

【中文标题】如何优化此 SQL Server 查询 - 多个子查询【英文标题】:How to optimize this SQL Server query - Multiple subqueries 【发布时间】:2020-07-24 22:41:07 【问题描述】:

我在 SQL Server 中有这个带有 4 个子查询的查询,我正在寻找优化它的方法:

 DECLARE @INICIO DATE
 DECLARE @FIN DATE
 SET @INICIO='2020-06-17'
 SET @FIN='2020-07-27'

 SELECT VALO.FECHA_VALORACION,
        VALO.CODIGO_PORTAFOLIO,
        VALO.CUSIP,
        VALO.NUMERO_INVERSION,
        VALO.SM_GRUPO 
        SM_TIPO,
        VALO.TIPO_INSTRUMENTO DESCRIPCION_INSTMT,
        VALO.CODIGO_MONEDA CODIGO_MONEDA_PAGAR, 
        VALO.CODIGO_MONEDA CODIGO_MONEDA_RECIBIR,
        VALO.ID_CONTRAPARTE,
        OP.PRECIO 
        PRECIO_FX,
        VALO.VALOR_NOMINAL,
        VALO.VALOR_DERECHO,
        VALO.VALOR_OBLIGACION,
        VALO.VALOR_UTILIDAD_PERDIDA, 
        OP.FECHA FECHA_OPERACION,
        VALO.TIPO_OPERACION,
        OP.VALOR_OPERACION  VALOR_OPERACION_COP,
        OP.FECHA_VENCIMIENTO,
        VALO.SM_GRUPO,
        VALO.VALOR_UTILIDAD_PERDIDA_DER,
        VALO.VALOR_UTILIDAD_PERDIDA_OBL,
        (SELECT SUM(NESTED.VALOR_UTILIDAD_PERDIDA)
         FROM Spirit.TSPT_VALORACION_FUT NESTED 
         WHERE NESTED.CUSIP=VALO.CUSIP
           AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO 
           AND FECHA_VALORACION>=dateadd(month, datediff(month, 0, @INICIO), 0)
           AND FECHA_VALORACION<=VALO.FECHA_VALORACION 
           AND VALOR_UTILIDAD_PERDIDA>0
         GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS UTILIDAD_MENSUAL,
        (SELECT SUM(NESTED.VALOR_UTILIDAD_PERDIDA)
         FROM Spirit.TSPT_VALORACION_FUT NESTED 
         WHERE NESTED.CUSIP=VALO.CUSIP
           AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO 
           AND FECHA_VALORACION>=dateadd(month, datediff(month, 0, @INICIO), 0)
           AND FECHA_VALORACION<=VALO.FECHA_VALORACION 
           AND VALOR_UTILIDAD_PERDIDA<0
         GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS PERDIDA_MENSUAL,
        (SELECT SUM(NESTED.VALOR_UTILIDAD_PERDIDA)
         FROM Spirit.TSPT_VALORACION_FUT NESTED 
         WHERE NESTED.CUSIP=VALO.CUSIP
         AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO 
           AND NESTED.FECHA_VALORACION<=VALO.FECHA_VALORACION 
           AND NESTED.VALOR_UTILIDAD_PERDIDA>0
         GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS UTILIDAD_ACUMULADA,
        (SELECT SUM(NESTED.VALOR_UTILIDAD_PERDIDA)
         FROM Spirit.TSPT_VALORACION_FUT NESTED 
         WHERE NESTED.CUSIP=VALO.CUSIP
           AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO 
           AND FECHA_VALORACION<=VALO.FECHA_VALORACION
           AND VALOR_UTILIDAD_PERDIDA<0
         GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS PERDIDA_ACUMULADA
FROM Spirit.TSPT_VALORACION_FUT VALO 
     INNER JOIN Spirit.TSPT_OPERACIONES OP ON OP.NUMERO_INVERSION = VALO.NUMERO_INVERSION
            AND OP.TIPO_OPERACION = VALO.TIPO_OPERACION
            AND OP.SM_GRUPO IN ('OPTION') 
WHERE VALO.SM_GRUPO IN ('OPTION')
  AND VALO.CODIGO_PORTAFOLIO IN ('AFP-P','AFP-F')
  AND VALO.FECHA_VALORACION >= @INICIO
  AND VALO.FECHA_VALORACION <= @FIN
ORDER BY VALO.CUSIP,VALO.FECHA_VALORACION

但我不知道如何整合它并获得最佳效果。非常感谢。

这是之前优化过程的结果。

我一直在尝试这样的:

(SELECT sum (case when NESTED.VALOR_UTILIDAD_PERDIDA > 0 then NESTED.VALOR_UTILIDAD_PERDIDA else 0 end) as UTILIDAD_MENSUAL,
        sum (case when NESTED.VALOR_UTILIDAD_PERDIDA < 0 then  NESTED.VALOR_UTILIDAD_PERDIDA else 0 end) as PERDIDA_MENSUAL
    FROM Spirit.TSPT_VALORACION_FUT NESTED 
WHERE NESTED.CUSIP=VALO.CUSIP
  AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO 
  AND FECHA_VALORACION>=dateadd(month, datediff(month, 0, @INICIO), 0) 
  AND FECHA_VALORACION<=VALO.FECHA_VALORACION 
  AND VALOR_UTILIDAD_PERDIDA>0
GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS ACUMULADOS

【问题讨论】:

仅供参考,空格和换行符使 SQL 可读。 【参考方案1】:

由于您的所有子查询似乎都来自同一个表,您可以将它们合并到 FROM 子句中的单个查询中...试试这个...如果没有要引用的表架构 ...

DECLARE @INICIO DATE
DECLARE @FIN DATE

SET @INICIO='2020-06-17'
SET @FIN='2020-07-27'

SELECT
    VALO.FECHA_VALORACION,
    VALO.CODIGO_PORTAFOLIO,
    VALO.CUSIP,
    VALO.NUMERO_INVERSION,
    VALO.SM_GRUPO
    SM_TIPO,
    VALO.TIPO_INSTRUMENTO DESCRIPCION_INSTMT,
    VALO.CODIGO_MONEDA CODIGO_MONEDA_PAGAR,
    VALO.CODIGO_MONEDA CODIGO_MONEDA_RECIBIR,
    VALO.ID_CONTRAPARTE,
    OP.PRECIO
    PRECIO_FX,
    VALO.VALOR_NOMINAL,
    VALO.VALOR_DERECHO,
    VALO.VALOR_OBLIGACION,
    VALO.VALOR_UTILIDAD_PERDIDA,
    OP.FECHA FECHA_OPERACION,
    VALO.TIPO_OPERACION,
    OP.VALOR_OPERACION VALOR_OPERACION_COP,
    OP.FECHA_VENCIMIENTO,
    VALO.SM_GRUPO,
    VALO.VALOR_UTILIDAD_PERDIDA_DER,
    VALO.VALOR_UTILIDAD_PERDIDA_OBL,
    S.UTILIDAD_MENSUAL,
    S.PERDIDA_MENSUAL,
    S.UTILIDAD_ACUMULADA,
    S.PERDIDA_ACUMULADA
FROM
    Spirit.TSPT_VALORACION_FUT VALO
    INNER JOIN Spirit.TSPT_OPERACIONES OP ON
        OP.NUMERO_INVERSION = VALO.NUMERO_INVERSION
        AND OP.TIPO_OPERACION = VALO.TIPO_OPERACION
        AND OP.SM_GRUPO IN ('OPTION')
    OUTER APPLY (
        SELECT
            SUM(CASE WHEN FECHA_VALORACION>=dateadd(month, datediff(month, 0, @INICIO), 0) AND VALOR_UTILIDAD_PERDIDA>0
                THEN NESTED.VALOR_UTILIDAD_PERDIDA
                ELSE 0
            END) UTILIDAD_MENSUAL,

            SUM(CASE WHEN  FECHA_VALORACION>=dateadd(month, datediff(month, 0, @INICIO), 0) AND VALOR_UTILIDAD_PERDIDA<0 
                THEN NESTED.VALOR_UTILIDAD_PERDIDA
                ELSE 0
            END) PERDIDA_MENSUAL,

            SUM(CASE WHEN NESTED.VALOR_UTILIDAD_PERDIDA>0 
                THEN NESTED.VALOR_UTILIDAD_PERDIDA
                ELSE 0
            END) UTILIDAD_ACUMULADA,

            SUM(CASE WHEN VALOR_UTILIDAD_PERDIDA<0
                THEN NESTED.VALOR_UTILIDAD_PERDIDA
                ELSE 0 END
            ) PERDIDA_ACUMULADA
        FROM
            Spirit.TSPT_VALORACION_FUT NESTED
        WHERE
            FECHA_VALORACION<=VALO.FECHA_VALORACION AND 
            NESTED.CUSIP = VALO.CUSIP AND
            NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO
        GROUP BY
            CUSIP,
            CODIGO_PORTAFOLIO
    ) S
WHERE
    VALO.SM_GRUPO IN ('OPTION')
    AND VALO.CODIGO_PORTAFOLIO IN ('AFP-P','AFP-F')
    AND VALO.FECHA_VALORACION >= @INICIO
    AND VALO.FECHA_VALORACION <= @FIN
ORDER BY
    VALO.CUSIP,
    VALO.FECHA_VALORACION

【讨论】:

它告诉我:“在包含外部引用的聚合表达式中指定了多个列。如果正在聚合的表达式包含外部引用,则该外部引用必须是表达式中引用的唯一列。 " Line " SUM(CASE WHEN FECHA_VALORACION>=dateadd(month, datediff(month, 0, @INICIO), 0) AND FECHA_VALORACION0 THEN NESTED.VALOR_UTILIDAD_PERDIDA ELSE 0 END) UTILIDAD_MENSUAL" 没问题...你能给我一个查询中的两个表的 CREATE TABLE 定义吗? 试试这个...我能够将更常见的条件从 CASE 语句中移到 WHERE CLAUSE 中。

以上是关于如何优化此 SQL Server 查询 - 多个子查询的主要内容,如果未能解决你的问题,请参考以下文章

从多个表中创建 Sql Server VIEW GROUPing BY,选择子查询作为别名

如何在子查询 SQL Server 中选择多个项目

如何避免多个子查询作为表达式(SQL优化)

优化 SQL:如何重写此查询以提高性能? (使用子查询,摆脱 GROUP BY?)

有关优化此多层(具有多层子查询)SQL 查询的提示

如何编写此查询以在 Sql Server 中获得更好的性能?删除子字符串行