查询在 SQL Server 2014 中很慢,在 SQL Server 2012 中很快

use*_*710 7 performance sql-server execution-plan sql-server-2014 query-performance

在将我们的一个数据库从 SQL Server 2012 (SP1, CU2) 迁移到 SQL Server 2014 (SP1) 的过程中,我们遇到了一些奇怪的问题。

在 SQL Server 2012 上几秒钟内完成的查询之一似乎挂在 SQL Server 2014 上。

SELECT  DISTINCT 
    src.[Id]
FROM
    [stg].[BaseVolumes] src
JOIN     
    [tmp].[Dates] d ON src.[CalWeek_Nmbr] = d.[CalYrWkDense_Nmbr]
WHERE   
    EXISTS (SELECT  *
            FROM    
                (SELECT     ctry.[ISOCode]                  AS  [Mkt_Code]
                            , so.[Code]                     AS  [SlsOrg_Code_AK]
                            , so.[DistributionChannelCode]  AS  [DistChnl_Code_AK]
                            , prd.[SupplierCode]                AS  [SKU_Code_AK]
                            , cl6.[Code]                        AS  [CstHierLvl06_Code_AK]
                            , lp.[BaseDateID]                   AS  [Dte_EK]
                 FROM   [PM_APP].[edw].[BaseVolumeDayCurrent]   lp
                 JOIN   [PM_APP].[dbo].[Country]                ctry    ON  lp.[CountryID] = ctry.[ID]
                 JOIN   [PM_APP].[dbo].[SalesOrganisation]      so      ON  lp.[SalesOrganisationID] = so.[ID]
                 JOIN   [PM_APP].[dbo].[Product]                prd     ON  lp.[ProductID] = prd.[ID]   
                 JOIN   [PM_APP].[dbo].[CustomerLevel6]         cl6     ON  lp.[CustomerID] = cl6.[ID]
                 WHERE  
                     lp.[ModifiedByApp] = 1) lkp
            WHERE   
                src.[Mkt_Code]                  =   lkp.[Mkt_Code]
                AND src.[SlsOrg_Code_AK]        =   lkp.[SlsOrg_Code_AK]
                AND src.[DistChnl_Code_AK]      =   lkp.[DistChnl_Code_AK]
                AND src.[SKU_Code_AK]           =   lkp.[SKU_Code_AK]
                AND src.[CstHierLvl06_Code_AK]  =   lkp.[CstHierLvl06_Code_AK]
                AND d.[Dte_EK]                  =   lkp.[Dte_EK]
        )
Run Code Online (Sandbox Code Playgroud)

行数:

BaseVolumes:            23108 
Dates:                  18628 
BaseVolumeDayCurrent:   108115503 
Country:                249
SalesOrganisation:      29
Product:                18446
CustomerLevel6:         295
Run Code Online (Sandbox Code Playgroud)

等待统计数据显示高 CXPacket,但有一个挂起的任务与 SOS_SCHEDULER_YIELD,(从 sys.sysprocesses 打印)

 spid | blocked | waittime | lastwaittype          | cpu     | physical_io 
 76   | 0       | 9886044  | CXPACKET              | 13902   | 31192
 76   | 0       | 0        | SOS_SCHEDULER_YIELD   | 9829719 | 83077
 76   | 0       | 11248    | CXPACKET              | 11110   | 0
.
.
.
Run Code Online (Sandbox Code Playgroud)

附件是 SQL Server 2012 和 SQL Server 2014 的执行计划。

非常感谢任何帮助。

Geo*_*son 10

最有可能的情况是,新的 SQL 2014 Cardinality Estimator对查询中的一个或多个连接产生了较差的行估计,这导致 SQL Server 选择了一个低效的计划。

如果您能够在打开“包含实际执行计划”的情况下在 SQL 2014 中运行查询,则可以在另一个选项卡中使用下面的查询来查看流经每个查询运算符的行的实时进度。我注意到您只有 2014 年的估计计划(与 2012 年的实际计划相比),大概是因为您无法在 SQL 2014 中运行查询以完成。因此,这可以让您更深入地了解流经查询的实际行2014 年,并且可能会引导您使用新的基数估算器来调整有效运行的查询的方法。

同时,在您能够优化查询之前,您可以将此查询QUERYTRACEON 与跟踪标志 9481 一起使用或者您可以按照Brent Ozar 的建议在 SQL 2012 兼容级别运行数据库,使用新的基数估算器仔细测试您的查询,并且只有在对这些结果感到满意后才将兼容级别更新为 120 (SQL 2014)。

/* Live query progress in SQL 2014 */
SELECT session_id,node_id,physical_operator_name, SUM(row_count) row_count, SUM(estimate_row_count) AS estimate_row_count, 
    CAST(SUM(row_count)*100 AS float)/NULLIF(SUM(estimate_row_count),0) AS percent_complete,
    SUM(elapsed_time_ms) AS elapsed_time_ms,
    SUM(cpu_time_ms) AS cpu_time_ms,
    SUM(logical_read_count) AS logical_read_count,
    SUM(physical_read_count) AS physical_read_count,
    SUM(write_page_count) AS spill_page_count,
    SUM(segment_read_count) AS segment_read_count,
    SUM(segment_skip_count) AS segment_skip_count,
    COUNT(*) AS num_threads
FROM sys.dm_exec_query_profiles 
WHERE session_id <> @@spid
GROUP BY session_id,node_id,physical_operator_name
ORDER BY session_id,node_id;
Run Code Online (Sandbox Code Playgroud)