web-dev-qa-db-ja.com

UserDB選択の特定のTempDB挿入により、SOS_SCHEDULER_YIELDからENCRYPTION_SCANが返されます。

実稼働システムの1つで、ユーザーデータベースから一時テーブルへの1つの挿入ステートメントに問題が発生しています。挿入/選択をコメントアウトすると、問題のストアドプロシージャがタイムリーに実行されるので、問題の切り分けに自信があります。

問題の挿入/選択のコメントを解除すると、呼び出された一連のストアドプロシージャが基本的に停止して停止します。 tempdbまたはユーザーデータベースで、年齢別の上位トランザクションに何も表示されません。データベースが「静止」しているときに、アクティビティモニターの情報から逸脱するアクティビティモニターには何も表示されません。ただし、CPUは約20%で平坦化されます。

動作は次のとおりです。再生ケースをセットアップして実行すると、問題の挿入/選択に到達すると、SOS_SCHEDULER_YIELDが表示され、ENCRYPTION_SCANがあります。約5時間後、ストアドプロシージャの処理が再開し、アクティビティが完了します(すべての個別の操作の周りに、迅速でダーティなログステートメントを配置します)。

また、挿入の選択部分の変数を実行時の値に置き換え、選択クエリ自体を実行したところ、5秒で戻りました。

問題のユーザーデータベースは、tempdbと同様に、暗号化が有効な値としてFALSEを持っています。問題の操作は約6万5千行のデータで発生し、1千行のみで試してみましたが、動作は持続しましたが、所要時間ははるかに短くなりました。

シングルユーザーデータベースは、この動作の唯一のインスタンスです。そのユーザーデータベースのバックアップを介してローカルで再現しました。この問題を示さないソフトウェアのユーザーが約70人います。

上記の情報を踏まえて、私の質問は、ストアドプロシージャの処理が停止するのはなぜですか?正確な答えを期待することはおそらく楽観的であるため、これをデバッグするための正しい手順は何ですか?おそらく、dm_tran_locks、dm_exec_requests、dm_tran_database_transactions、dm_os_schedulers、dm_exec_sessionsなどのDMVの1つに何かがあり、それらは私にいくつかの情報を提供しましたが、解決策を指すような方法で出力を解釈または理解していません。

以下は問題の挿入/選択です:

INSERT INTO #TS_EVENT_DATA 
        (   EVENT_FK,
            EVENT_TYPE_CR_FK,
            EVENT_ENTITY_CLASS_CR_FK,
            userDatabase_ID,
            DATA_NAME_FK,               
            IMPORT_JOB_FK,              
            PRODUCT_STRUCTURE_FK,
            ORG_ENTITY_STRUCTURE_FK,
            ENTITY_CLASS_CR_FK,
            ENTITY_DATA_NAME_FK,
            ENTITY_STRUCTURE_FK,                
            DATA_SET_FK,
            DATA_TYPE_CR_FK,
            ORG_IND,
            TABLE_NAME,
            NET_VALUE1_NEW,
            NET_VALUE2_NEW,
            NET_VALUE3_NEW,
            NET_VALUE4_NEW,
            NET_VALUE5_NEW,
            NET_VALUE6_NEW,                                                     
            NET_VALUE1_CUR,
            NET_VALUE2_CUR,
            NET_VALUE3_CUR,
            NET_VALUE4_CUR,
            NET_VALUE5_CUR,
            NET_VALUE6_CUR,                         
            PERCENT_CHANGE1,
            PERCENT_CHANGE2,
            PERCENT_CHANGE3,
            PERCENT_CHANGE4,
            PERCENT_CHANGE5,
            PERCENT_CHANGE6,                            
            VALUE_UOM_CODE_FK,
            ASSOC_UOM_CODE_FK,
            VALUES_SHEET_NAME,
            UOM_CONVERSION_FACTOR,
            END_DATE_CUR,                           
            END_DATE_NEW,   
            EFFECTIVE_DATE_CUR,                                     
            EVENT_EFFECTIVE_DATE,
            EVENT_ACTION_CR_FK,
            EVENT_STATUS_CR_FK, 
            EVENT_CONDITION_CR_FK,
            EVENT_SOURCE_CR_FK,
            EVENT_PRIORITY_CR_FK,
            RESULT_TYPE_CR_FK,
            TABLE_ID_FK,
            BATCH_NO,
            IMPORT_BATCH_NO,
            RULES_FK,
            RECORD_STATUS_CR_FK,                
            UPDATE_TIMESTAMP
             )  
   SELECT
            A.EVENT_ID,                    
            A.EVENT_TYPE_CR_FK,
            A.EVENT_ENTITY_CLASS_CR_FK,
            A.userDatabase_ID,
            A.DATA_NAME_FK,             
            A.IMPORT_JOB_FK,
            A.PRODUCT_STRUCTURE_FK,
            A.ORG_ENTITY_STRUCTURE_FK,
            A.ENTITY_CLASS_CR_FK,
            A.ENTITY_DATA_NAME_FK,
            A.ENTITY_STRUCTURE_FK,
            A.DATA_SET_FK,
            A.DATA_TYPE_CR_FK,
            A.ORG_IND,
            A.TABLE_NAME,
            A.NET_VALUE1_NEW,
            A.NET_VALUE2_NEW,
            A.NET_VALUE3_NEW,
            A.NET_VALUE4_NEW,
            A.NET_VALUE5_NEW,
            A.NET_VALUE6_NEW,                                                   
            A.NET_VALUE1,  
            A.NET_VALUE2,
            A.NET_VALUE3,
            A.NET_VALUE4,
            A.NET_VALUE5,
            A.NET_VALUE6,                       
            CASE ISNULL (A.NET_VALUE1, 0 )
             WHEN 0 THEN 0  
             ELSE ( ( A.NET_VALUE1_NEW  - A.NET_VALUE1) / A.NET_VALUE1 )
             END,
            CASE ISNULL (A.NET_VALUE2, 0 )
             WHEN 0 THEN 0  
             ELSE ( ( A.NET_VALUE2_NEW  - A.NET_VALUE2 ) / A.NET_VALUE2 )
             END,
            CASE ISNULL (A.NET_VALUE3, 0 )
             WHEN 0 THEN 0  
             ELSE ( ( A.NET_VALUE3_NEW  - A.NET_VALUE3 ) / A.NET_VALUE3 )
             END,
            CASE ISNULL (A.NET_VALUE4, 0 )
             WHEN 0 THEN 0  
             ELSE ( ( A.NET_VALUE4_NEW  - A.NET_VALUE4 ) / A.NET_VALUE4 )
             END,
            CASE ISNULL (A.NET_VALUE5, 0 )
             WHEN 0 THEN 0  
             ELSE ( ( A.NET_VALUE5_NEW  - A.NET_VALUE5 ) / A.NET_VALUE5 )
             END,
            CASE ISNULL (A.NET_VALUE6, 0 )
             WHEN 0 THEN 0  
             ELSE ( ( A.NET_VALUE6_NEW  - A.NET_VALUE6 ) / A.NET_VALUE6 )
             END,
        A.VALUE_UOM_CODE_FK,
        A.ASSOC_UOM_CODE_FK,
        A.VALUES_SHEET_NAME,
        ( SELECT CASE ISNULL ( A.VALUE_UOM_CODE_FK, 0 ) 
        WHEN 0 THEN 1
        ELSE
        CASE ISNULL ( A.ASSOC_UOM_CODE_FK, 0 ) 
        WHEN 0 THEN 1
        ELSE
        ( ISNULL (
        ( SELECT 
        ( SELECT ISNULL (
           (SELECT uc.primary_qty
            FROM userDatabase.UOM_CODE uc WITH (NOLOCK)
            WHERE uc.UOM_CODE_ID = A.VALUE_UOM_CODE_FK  ), 1 )
        )
        /
        ISNULL (   (SELECT uc.primary_qty
                    FROM userDatabase.UOM_CODE uc WITH (NOLOCK)
                    WHERE uc.UOM_CODE_ID = A.ASSOC_UOM_CODE_FK )
                 , ISNULL ( (SELECT uc.primary_qty
                             FROM userDatabase.UOM_CODE uc WITH (NOLOCK)
                             WHERE uc.UOM_CODE_ID = A.VALUE_UOM_CODE_FK) , 1 ) 
                 )
        ) , 1 ) )
        END END
        )  AS UOM_CONVERSION_FACTOR,
            A.END_DATE,
            A.END_DATE_NEW, 
            A.EFFECTIVE_DATE,                                       
            A.EVENT_EFFECTIVE_DATE,
            A.EVENT_ACTION_CR_FK,
            A.EVENT_STATUS_CR_FK,   
            A.EVENT_CONDITION_CR_FK,
            A.EVENT_SOURCE_CR_FK,
            A.EVENT_PRIORITY_CR_FK,
            A.RESULT_TYPE_CR_FK,
            A.SHEET_RESULTS_ID,
            A.BATCH_NO,
            A.IMPORT_BATCH_NO,
            A.RULES_FK,
            A.RECORD_STATUS_CR_FK,              
            @L_SYSDATE

FROM ( SELECT
            ED.EVENT_ID,                    
            DS.EVENT_TYPE_CR_FK,
            DS.ENTITY_CLASS_CR_FK AS EVENT_ENTITY_CLASS_CR_FK,
            ED.PRODUCT_STRUCTURE_FK AS userDatabase_ID,
            ED.DATA_NAME_FK,
            ED.IMPORT_JOB_FK,           
            ED.PRODUCT_STRUCTURE_FK,
            CASE ISNULL ( DS.ORG_IND, 0 )
            WHEN 0 THEN ISNULL ( ED.ORG_ENTITY_STRUCTURE_FK, 1 )
            ELSE ED.ORG_ENTITY_STRUCTURE_FK         
            END AS ORG_ENTITY_STRUCTURE_FK,
            DS.ENTITY_STRUCTURE_EC_CR_FK AS ENTITY_CLASS_CR_FK,
            DN.ENTITY_DATA_NAME_FK,
            ED.ENTITY_STRUCTURE_FK,                                                                                 
            DN.DATA_SET_FK,
            DS.DATA_TYPE_CR_FK,
            DS.ORG_IND,
            DS.TABLE_NAME,
            ED.NET_VALUE1_NEW,
            ED.NET_VALUE2_NEW,
            ED.NET_VALUE3_NEW,
            ED.NET_VALUE4_NEW,
            ED.NET_VALUE5_NEW,
            ED.NET_VALUE6_NEW,                                                      
            SR.NET_VALUE1,
            SR.NET_VALUE2,
            SR.NET_VALUE3,
            SR.NET_VALUE4,
            SR.NET_VALUE5,
            SR.NET_VALUE6,  
        ED.VALUE_UOM_CODE_FK,               
        ( SELECT TOP 1 PUC.UOM_CODE_FK
          FROM userDatabase.PRODUCT_UOM_CLASS PUC WITH (NOLOCK)
          WHERE ( PUC.DATA_NAME_FK = DN.UOM_CLASS_DATA_NAME_FK
          AND     PUC.PRODUCT_STRUCTURE_FK = ED.PRODUCT_STRUCTURE_FK
          AND   (  (   DS.ORG_IND = 1
                   AND PUC.ORG_ENTITY_STRUCTURE_FK = ED.ORG_ENTITY_STRUCTURE_FK )
                  OR PUC.ORG_ENTITY_STRUCTURE_FK = 1 ) 
          AND ISNULL ( PUC.ENTITY_STRUCTURE_FK, -999 ) = ISNULL ( ED.ENTITY_STRUCTURE_FK, -999 )   )
        ) AS ASSOC_UOM_CODE_FK,
        ED.VALUES_SHEET_NAME,
            SR.END_DATE,
            ED.END_DATE_NEW,
            SR.EFFECTIVE_DATE,              
            ED.EVENT_EFFECTIVE_DATE, 
            CASE WHEN ED.EVENT_ACTION_CR_FK = 59
            THEN 59
            ELSE
            CASE WHEN SR.SHEET_RESULTS_ID IS NULL
            THEN 51
            ELSE 52
            END
            END  AS EVENT_ACTION_CR_FK,
            ED.EVENT_STATUS_CR_FK,  
            ED.EVENT_CONDITION_CR_FK,
            ED.EVENT_SOURCE_CR_FK,
            ED.EVENT_PRIORITY_CR_FK,
            ISNULL ( ED.RESULT_TYPE_CR_FK, 711 ) AS RESULT_TYPE_CR_FK,                  
            SR.SHEET_RESULTS_ID,
            ED.BATCH_NO,
            ED.IMPORT_BATCH_NO,
            ED.RULES_FK,
            ED.RECORD_STATUS_CR_FK          
 FROM SYNCHRONIZER.EVENT_DATA ED WITH (NOLOCK)
    INNER JOIN userDatabase.DATA_NAME DN WITH (NOLOCK)
     ON ( DN.DATA_NAME_ID = ED.DATA_NAME_FK )
    INNER JOIN userDatabase.DATA_SET DS WITH (NOLOCK)
     ON ( DS.DATA_SET_ID = DN.DATA_SET_FK )
    LEFT JOIN marginmgr.SHEET_RESULTS SR WITH (NOLOCK)
     ON ( SR.DATA_NAME_FK = ED.DATA_NAME_FK
     AND  ISNULL ( SR.PRODUCT_STRUCTURE_FK, 0 ) = ISNULL ( ED.PRODUCT_STRUCTURE_FK, 0 )
     AND  ISNULL ( SR.ORG_ENTITY_STRUCTURE_FK, 0 ) = ISNULL ( ED.ORG_ENTITY_STRUCTURE_FK, 1 )
     AND  ISNULL ( SR.ENTITY_STRUCTURE_FK, 0 ) = ISNULL ( ED.ENTITY_STRUCTURE_FK, 0 )  
    )                                                    
    WHERE 1 = 1 
    AND  EVENT_STATUS_CR_FK = 88        
    AND (   
           (    ISNULL ( @in_event_fk, -999 ) = -999
            AND ISNULL ( ED.BATCH_NO, -999 ) = ISNULL ( @in_batch_no, -999 )
            AND ISNULL ( ED.import_job_fk, -999 ) = ISNULL (@in_import_job_fk, -999 )
            AND isnull ( ED.event_priority_cr_fk, -999 ) = isnull (@in_event_priority_cr_fk, -999)
            AND ISNULL ( ds.table_name, 'NULL DATA' )  = ISNULL ( @in_table_name, 'NULL DATA' ) )
        OR  ED.EVENT_ID = ISNULL (@in_event_fk, -999 ) 
        )
    AND   (   @in_data_name_fk = -999           
          OR  ED.data_name_fk = @in_data_name_fk )          
) A 

Sp_configureの結果:

access check cache bucket count 0   65536   0   0
access check cache quota    0   2147483647  0   0
Ad Hoc Distributed Queries  0   1   0   0
affinity I/O mask   -2147483648 2147483647  0   0
affinity mask   -2147483648 2147483647  0   0
affinity64 I/O mask -2147483648 2147483647  0   0
affinity64 mask -2147483648 2147483647  0   0
Agent XPs   0   1   1   1
allow updates   0   1   0   0
backup compression default  0   1   0   0
blocked process threshold (s)   0   86400   0   0
c2 audit mode   0   1   0   0
clr enabled 0   1   1   1
common criteria compliance enabled  0   1   0   0
contained database authentication   0   1   0   0
cost threshold for parallelism  0   32767   5   5
cross db ownership chaining 0   1   0   0
cursor threshold    -1  2147483647  -1  -1
Database Mail XPs   0   1   1   1
default full-text language  0   2147483647  1033    1033
default language    0   9999    0   0
default trace enabled   0   1   1   1
disallow results from triggers  0   1   0   0
EKM provider enabled    0   1   0   0
filestream access level 0   2   0   0
fill factor (%) 0   100 0   0
ft crawl bandwidth (max)    0   32767   100 100
ft crawl bandwidth (min)    0   32767   0   0
ft notify bandwidth (max)   0   32767   100 100
ft notify bandwidth (min)   0   32767   0   0
index create memory (KB)    704 2147483647  0   0
in-doubt xact resolution    0   2   0   0
lightweight pooling 0   1   0   0
locks   5000    2147483647  0   0
max degree of parallelism   0   32767   0   0
max full-text crawl range   0   256 4   4
max server memory (MB)  128 2147483647  5120    5120
max text repl size (B)  -1  2147483647  65536   65536
max worker threads  128 65535   0   0
media retention 0   365 0   0
min memory per query (KB)   512 2147483647  1024    1024
min server memory (MB)  0   2147483647  128 128
nested triggers 0   1   1   1
network packet size (B) 512 32767   4096    4096
Ole Automation Procedures   0   1   0   0
open objects    0   2147483647  0   0
optimize for ad hoc workloads   0   1   0   0
PH timeout (s)  1   3600    60  60
precompute rank 0   1   0   0
priority boost  0   1   0   0
query governor cost limit   0   2147483647  0   0
query wait (s)  -1  2147483647  -1  -1
recovery interval (min) 0   32767   0   0
remote access   0   1   1   1
remote admin connections    0   1   0   0
remote login timeout (s)    0   2147483647  10  10
remote proc trans   0   1   0   0
remote query timeout (s)    0   2147483647  600 600
Replication XPs 0   1   0   0
scan for startup procs  0   1   0   0
server trigger recursion    0   1   1   1
set working set size    0   1   0   0
show advanced options   0   1   1   1
SMO and DMO XPs 0   1   1   1
transform noise words   0   1   0   0
two digit year cutoff   1753    9999    2049    2049
user connections    0   32767   0   0
user options    0   32767   0   0
xp_cmdshell 0   1   1   1

リンク 実行計画のXMLに(埋め込みするには大きすぎます)。

8
Robert Gannon

暗号化(TDEなど)が使用されている場合、待機リストにENCRYPTION_SCANリソースが表示されるだけではありません。

特定の操作では、このリソースを共有ロックして、操作中にデータベースが暗号化されないようにします。

TDEを使​​用してユーザーデータベースを暗号化すると、tempdbも暗号化されます(そうしないと、ユーザーデータがtemp dbで使用されるときにセキュリティリスクが発生します)。

したがって、一部の操作では、TempdbのENCRYPTION_SCANで共有ロックを取得して、Tempdbが暗号化されないようにします。

次に2つの例を示します。

一括挿入

IF object_id('tempdb..##NumberCreation') IS NOT NULL
    drop table ##NumberCreation
GO

--create temp table to hold numbers
create table ##NumberCreation (C int NOT NULL);
GO

-- CREATE Numbers by using trick from Itzik -> http://sqlmag.com/sql-server/virtual-auxiliary-table-numbers 
WITH L1 AS ( SELECT 1 as C UNION SELECT 0 ),
    L2 AS ( SELECT 1 as C FROM L1 CROSS JOIN L1 as B ),
    L3 AS ( SELECT 1 as C FROM L2 CROSS JOIN L2 as B ),
    L4 AS ( SELECT 1 as C FROM L3 CROSS JOIN L3 as B ),
    L5 AS ( SELECT 1 as C FROM L4 CROSS JOIN L4 as B ),
    L6 AS ( SELECT 1 as C FROM L5 CROSS JOIN L5 as B),
    Nums as (SELECT ROW_NUMBER() OVER (ORDER BY C) as C FROM L6) 
insert ##NumberCreation(C)
SELECT TOP 500000 C
FROM Nums

上記のコードは、グローバル一時テーブルに500kレコードを生成します。次のコマンドでこれらをエクスポートできます。これをSSMSから実行する場合は、SQLCMDモードになっていることを確認してください。

--Export
!!bcp ##NumberCreation out "E:\SQLServer\Backup\test\export.dat" -T -n

--format file
!!bcp ##NumberCreation format nul -T -n  -f "E:\SQLServer\Backup\test\export.fmt"

SQL Serverサービスアカウントに書き込み権限があるディレクトリを選択してください。これをSSMSから実行する場合は、SQL Serverでローカルに実行してください。

次に、一括挿入ループを開始します。ループの実行中に2番目の画面を開き、DB_ID 2(Tempdb)にENCRYPTION_SCAN共有ロックが表示されるまで、sp_lockの実行を開始します。

一括インポートループ:

BEGIN
    IF OBJECT_ID('tempdb..#Import') IS NOT NULL
        DROP TABLE #Import ;

    CREATE TABLE #Import (C INT) ;
    BULK INSERT #Import
    FROM 'E:\SQLServer\Backup\test\export.dat' WITH (FORMATFILE='E:\SQLServer\Backup\test\export.fmt', FIRSTROW=1, TABLOCK) ;
END
GO 500 --run it 500 times

2番目のウィンドウでsp_lockの結果を確認します。

enter image description here

TEMPDBに並べ替え

同じTempテーブルを配置したら、次の非常に単純なループを開始します。

SELECT * from #Import order by C
go 50

次の実行計画が作成されます。

enter image description here

(#Importが実際に入力されていることを確認してください。前の一括インポートループをいつ停止したかによって、空になる可能性があります。)

再び、ENCRYPTION_SCANリソースがポップアップ表示されるまで、2番目のウィンドウでsp_lockを実行します。

enter image description here

これで、このリソース待機が表示される理由がわかりました。これがあなたの問題ではないことは非常によくあり得ます。 ENCRYPTION_SCANが表示される他の理由を指摘したいと思います。クエリが遅くなる理由は何か他にあるかもしれません。クエリプランの改善は、このサイトのクエリプランエキスパートに任せます;-)ただし、見積もりプランだけでなく、実際の実行プランも投稿できますか?

5
Edward Dortland