【问题标题】:Derived table where clause optimization派生表where子句优化
【发布时间】:2016-11-30 15:57:20
【问题描述】:

SQL 服务器管理工​​作室 2008 R2

我有一个视图(相当冗长的 sql 代码,是一系列派生表),多个不同的用户使用该视图在约 4,000,000 条记录上运行查询和存储过程。以下查询在大约 10 分钟内执行。

Select * from dbo.[vw_name]

我正在尝试使用相同的视图来提取 1 条记录的信息,但查询仍需要大约 10 分钟:

Select * from dbo.[vw_name] where ln=1234567890

似乎视图正在处理所有 4,000,000 条记录,然后应用我的 where 子句。我能够将视图复制到表值函数中,并将单条记录的查询时间增加到约 10 秒(我假设是因为我能够在第一个派生表中插入 where 子句,而不是在结尾)。关于如何强制优化器在查询视图时首先考虑 where 子句的任何想法?

添加视图查询:

SELECT      AsOfDate=GETDATE()
        ,A1.*
        ,Onsite_Flag=   CASE 
                        WHEN A1.[columnname]=1 AND A1.[columnname]=0 THEN 1
                        WHEN A1.[columnname]=5 AND A1.[columnname]=0 THEN 1
                        WHEN A1.[columnname] IN (12,31,33,34,35,38,52,54,59) THEN 1
                        ELSE 0 
                        END 
        ,A1.Allowable_Flag
        ,Achieved_Flag= CASE
                        WHEN A1.[columnname]=1 THEN
                            CASE
                            WHEN A1.[columnname] LIKE 'name%' 
                             AND A1.[columnname]>=A1.[columnname] 
                             AND (A1.[columnname] LIKE '%LOL%' OR A1.[columnname]='test') THEN 1
                            WHEN A1.[columnname]='qwerw' AND A1.[columnname]=4 THEN 1
                            WHEN A1.[columnname]='aerr33' AND A1.[columnname]=4 THEN 1
                            WHEN A1.[columnname]='asdf45' AND A1.[columnname] IS NOT NULL THEN 1
                            ELSE 0
                            END
                        ELSE 0
                        END
        ,IM_Flag=   CASE
                    WHEN A1.[columnname] IN(12,38) THEN 1
                    WHEN A1.[columnname]=1 AND A1.[columnname]=24 THEN 1
                    ELSE 0 
                    END
FROM        (SELECT     [columnname]....
                    ,[Name]=LTRIM(RTRIM(V1.A1FNAM)) + ' ' + LTRIM(RTRIM(V1.A1LNAM))
                    ,LocationType= CASE WHEN LH1.[columnname]=2 THEN nLT.[columnname] ELSE LT.[columnname] END
                    ,LocationTypeID=CASE WHEN LH1.[columnname]=2 THEN nLT.[columnname] ELSE LT.[columnname] END
                    ,Location=CASE
                                WHEN DLD1.[columnname] IS NULL THEN DLD1.[columnname] 
                                WHEN LH1.[columnname] IN (2,8) THEN DLD1.[columnname] + ' - ' + DLD2.[columnname]
                                ELSE DLD1.[columnname] 
                                END 
                    ,Allowable_Flag=    CASE
                                        WHEN CU1.[columnname]='1234' THEN 1
                                        WHEN FCM.[columnname]='Y' THEN 0
                                        WHEN MLD.[columnname]='24' THEN 0
                                        WHEN INV.[columnname] LIKE '436573456%' THEN 1
                                        WHEN INV.[columnname] LIKE '4526%' THEN 1
                                        WHEN DSR.[columnname]='1020' THEN 1
                                        ELSE 0
                                        END
                    ,RN=ROW_NUMBER()OVER(PARTITION BY L.LoanNumber ORDER BY (CASE WHEN DM.Departments_ID=24 THEN 1 ELSE 0 END) DESC,LH1.LocationDate DESC)
        FROM        server_name_3.dbo.[tablename] DSR
        LEFT JOIN ....
        OUTER APPLY SERVER_name_2.dbo.fnc_DT (LH1.[columnname], LH1.[columnname]) DLD1
        OUTER APPLY SERVER_name_2.dbo.fnc_DT (DLD1.[columnname], DLD1.[columnname]) DLD2
        LEFT JOIN   (SELECT  field1, field2,...
                    FROM server_name_3.dbo.SRVDSR DSR
                    LEFT JOIN ...
                    INNER JOIN (SELECT field1, MAX(field2) as field2 FROM SERVERNAME1.dbo.[tablename] WHERE field3=157 GROUP BY field1) CUO ON CUO.field1=R.field1
                    GROUP BY DSR.field1
                    ) CP_Req ON DSR.field1=CP_Req.field1

        ) A1    
WHERE A1.RN=1

【问题讨论】:

标签: sql sql-server tsql optimization sql-server-2008-r2


【解决方案1】:

(1) 确保“ln”字段上有索引。 (2) 发布视图的查询,我们会看到它可以被优化 - 如果出于安全目的需要混淆字段。

【讨论】:

  • 查看上面添加的sql
【解决方案2】:

如果您要搜索的行号来自该 ROW_NUMBER 函数,那么是的,它必须生成整个结果,然后才能向您发送那条记录。您可以尝试通过从视图本身中删除 GETDATE 和 ROW_NUMBER 来使查询更具确定性,并将这些字段包含在视图的查询中:

; WITH DateNow
AS ( 
    SELECT DateNow = GETDATE() 
    )
SELECT d1.DateNow
    , v1.*
    , ROW_NUMBER() OVER...
FROM YourView v1
    , DateNow d1

这仍将产生整个结果,但视图本身可能会更快。如果有帮助,我可以给你一些一般性的建议。双通配符搜索 '%foo%' 是性能杀手,但我知道您经常被它所困扰。您可以考虑将这些派生表转换为索引视图,或者将许多字符串比较添加到持久计算列中。我认为如果数据可能有些陈旧,最好的解决方案是在晚上运行一次此查询并将结果插入到单个表中,即数据集市,这样查询起来会非常快。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-04
    • 2021-11-04
    相关资源
    最近更新 更多