web-dev-qa-db-ja.com

SQL Server 2014ではクエリが遅く、SQL Server 2012ではクエリが速い

SQL Server 2012(SP1、CU2)からSQL Server 2014(SP1)へのデータベースの移行中に、いくつかの奇妙な問題が発生しました。

SQL Server 2012で数秒以内に完了するクエリの1つが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]
        )

行数:

BaseVolumes:            23108 
Dates:                  18628 
BaseVolumeDayCurrent:   108115503 
Country:                249
SalesOrganisation:      29
Product:                18446
CustomerLevel6:         295

高いCXPacketを示す統計を待機しますが、SOS_SCHEDULER_YIELDで1つのハングしているタスクがあります(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
.
.
.

添付されているのは、SQL Server 2012およびSQL Server 2014の実行計画です。

どんな助けも大歓迎です。

7
user2428710

最も可能性の高い状況は、 新しいSQL 2014 Cardinality Estimator がクエリ内の1つ以上の結合の行推定値を低下させ、SQL Serverが非効率的な計画を選択するようになったことです。

「実際の実行計画を含める」をオンにしてSQL 2014でクエリを実行できる場合は、以下のクエリを別のタブで使用して、各クエリ演算子を通過する行のリアルタイムの進行状況を表示できます。おそらくSQL 2014でクエリを完全に実行できないため、2014年の推定計画(2012年の実際の計画と比較して)しかないことに気付きました。これにより、クエリを通過する実際の行をより詳細に把握できます。新しいCardinality Estimatorを使用して効率的に実行されるクエリを微調整する方法につながる可能性があります。

それまでの間、クエリを最適化できるようになるまで、このクエリに対してQUERYTRACEONトレースフラグ9481付き を使用するか、または Brent Ozarのアドバイス of SQL 2012互換性レベルでデータベースを実行し、新しいCardinality Estimatorを使用してクエリを慎重にテストし、これらの結果に満足したら、互換性レベルを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;
10
Geoff Patterson