【问题标题】:SQL Server view optimization help (repeated subqueries, case when, and so on...)SQL Server 视图优化帮助(重复子查询、大小写等...)
【发布时间】:2011-06-15 02:05:06
【问题描述】:

我需要一些帮助来优化 MSSQL 视图,老实说,这对我的知识来说有点太复杂了。

视图运行良好,但我想使用更少的子查询或更好的结构来重写它,以简化它并使用更少的服务器资源。

主要问题是 CASE WHEN 相同子查询重复 4 次...我试图了解是否可以将其放入变量中并将其用于 CASE 而不是每次都重复查询但似乎不可能对我来说...

这是查询

SELECT     dbo.MACCHINE.id_macchina, [...] dbo.VIEW_CANTIERI.indirizzo,

(SELECT     TOP (1) data_fine
FROM          dbo.MANUTENZIONI
WHERE      (id_macchina = dbo.MACCHINE.id_macchina)
ORDER BY data_fine DESC)
AS ultima_manutenzione, 

DATEDIFF(day,
    (SELECT     TOP (1) data_fine
    FROM          dbo.MANUTENZIONI AS MANUTENZIONI_1
    WHERE      (id_macchina = dbo.MACCHINE.id_macchina)
    ORDER BY data_fine DESC), GETDATE())
AS data_diff, 

(CASE WHEN 
    stato = 0 
    THEN 'GREY' 
WHEN stato = 2 
    THEN 'BLACK' 
WHEN stato = 1 
    THEN
        (CASE WHEN 
            DATEDIFF(day,
            (SELECT     TOP (1) data_fine
            FROM          dbo.MANUTENZIONI AS MANUTENZIONI_1
            WHERE      (id_macchina = dbo.MACCHINE.id_macchina)
            ORDER BY data_fine DESC), GETDATE()) >= 90 
        THEN 'RED'

        WHEN 
            DATEDIFF(day,
            (SELECT     TOP (1) data_fine
            FROM          dbo.MANUTENZIONI AS MANUTENZIONI_1
            WHERE      (id_macchina = dbo.MACCHINE.id_macchina)
            ORDER BY data_fine DESC), GETDATE()) >= 80 
        THEN 'ORANGE' 

        WHEN
            DATEDIFF(day,
            (SELECT     TOP (1) data_fine
            FROM          dbo.MANUTENZIONI AS MANUTENZIONI_1
            WHERE      (id_macchina = dbo.MACCHINE.id_macchina)
            ORDER BY data_fine DESC), GETDATE()) >= 60 
        THEN 'YELLOW'

        WHEN
            (SELECT     TOP (1) data_fine
            FROM          dbo.MANUTENZIONI AS MANUTENZIONI_1
            WHERE      (id_macchina = dbo.MACCHINE.id_macchina)
            ORDER BY data_fine DESC) IS NULL
        THEN 'RED' ELSE 'GREEN' 

        END) 

END) 
AS colore FROM         dbo.MACCHINE INNER JOIN
                  dbo.MACCHINE_MODELLI ON dbo.MACCHINE.id_modello = dbo.MACCHINE_MODELLI.id_modello INNER JOIN
                  dbo.MACCHINE_TIPOLOGIE ON dbo.MACCHINE_MODELLI.id_tipologia = dbo.MACCHINE_TIPOLOGIE.id_tipologia INNER JOIN
                  dbo.VIEW_CANTIERI ON dbo.MACCHINE.id_cantiere = dbo.VIEW_CANTIERI.id_cantiere INNER JOIN
                  dbo.MACCHINE_PRODUTTORI ON dbo.MACCHINE_MODELLI.id_produttore = dbo.MACCHINE_PRODUTTORI.id_produttore INNER JOIN
                  dbo.CLIENTI ON dbo.VIEW_CANTIERI.id_cliente = dbo.CLIENTI.id_cliente WHERE     (dbo.MACCHINE._del = 'N')

非常感谢任何建议,如果您需要有关数据库的更多信息,我会尽力提供...

【问题讨论】:

    标签: sql sql-server sql-server-2005 query-optimization subquery


    【解决方案1】:

    抱歉,如果您已经这样做了,但我建议您使用 SHOWPLAN (ctrl+L) 或性能工具(如果您有的话)。确认确实是这些 CASE 语句导致了问题 - 瓶颈可能是连接之一,例如,缺少索引或过时的统计信息促进了错误的执行计划。

    如果读取视图的频率远高于写入视图的频率,或者它不需要完全最新的数据(即,您可以每天缓存结果并从昨晚的刷新中读取视图),考虑使用索引视图。这会将视图缓存为表,因此不会在每次从表中读取时执行操作(包括 CASE 和 JOIN)(具有索引也可以加快使用速度)。或者,如果只有最近的数据发生变化,您可以尝试按日期对索引视图进行分区。

    【讨论】:

    • 非常感谢您的建议:我会考虑使用索引视图,我不需要实时更新,所以应该是一个很好的改进!
    【解决方案2】:

    我注意到您使用的是 TOP(1),所以这必须是 2005 年或更高版本。您可以将 datediff 的结果保留在 OUTER APPLY 子查询中,以便只计算一次。

    SELECT
        M.id_macchina,
        [...],
        V.indirizzo,
        MA.data_fine AS ultima_manutenzione, 
        MA.data_diff, 
        CASE
        WHEN stato = 0 THEN 'GREY' 
        WHEN stato = 2 THEN 'BLACK' 
        WHEN stato = 1 THEN
            CASE
            WHEN MA.data_diff >= 90   THEN 'RED'
            WHEN MA.data_diff >= 80   THEN 'ORANGE' 
            WHEN MA.data_diff >= 60   THEN 'YELLOW'
            WHEN MA.data_fine IS NULL THEN 'RED'
            ELSE 'GREEN' 
            END
        END AS colore
    FROM dbo.MACCHINE M
    INNER JOIN dbo.MACCHINE_MODELLI I ON M.id_modello = I.id_modello
    INNER JOIN dbo.MACCHINE_TIPOLOGIE T ON I.id_tipologia = T.id_tipologia
    INNER JOIN dbo.VIEW_CANTIERI V ON M.id_cantiere = V.id_cantiere
    INNER JOIN dbo.MACCHINE_PRODUTTORI P ON I.id_produttore = P.id_produttore
    INNER JOIN dbo.CLIENTI C ON V.id_cliente = C.id_cliente
    OUTER APPLY (SELECT TOP (1)
                    MA.data_fine,
                    DATEDIFF(day, MA.data_fine, GETDATE()) AS data_diff
                FROM    dbo.MANUTENZIONI AS MA
                WHERE   MA.id_macchina = M.id_macchina
                ORDER BY MA.data_fine DESC) MA
    WHERE M._del = 'N'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-06
      • 2011-03-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-06
      • 1970-01-01
      相关资源
      最近更新 更多