UserDB选择结果的特定TempDB插入将SOS_SCHEDULER_YIELD中的结果转换为ENCRYPTION_SCAN


8

我们的其中一个生产系统出现了一个问题,即从我们的用户数据库向临时表插入一条插入语句。当我注释掉插入/选择时,有问题的存储过程会及时运行,因此我对问题的隔离很有信心。

当我取消注释有问题的插入/选择时,调用的一系列存储过程基本上停止了。在tempdb或我们的任何用户数据库中,我看不到“按年龄划分的热门交易”中的任何内容。当数据库处于“静止”状态时,我看不到活动监视器中有任何偏离活动监视器信息的东西,除了CPU的平坦度约为20%。

行为如下:当我设置然后执行重现情况时,到达有问题的插入/选择时,我看到一个SOS_SCHEDULER_YIELD并有一个ENCRYPTION_SCAN。大约五个小时后,我将看到对存储过程的处理恢复并且该活动将完成(我在每个不同的操作周围放入了快速且肮脏的日志语句)。

我还用执行时的值替换了插入的选择部分中的变量,并运行选择查询本身,并在五秒钟内将其返回。

有问题的用户数据库的加密启用值为FALSE,tempdb也是如此。有问题的操作发生在大约65k行数据上,我仅用1k行进行了尝试,并且这种行为仍然存在,尽管花费的时间要少得多。

单个用户数据库是此行为的唯一实例。我已经通过该用户数据库的备份在本地复制了它。我们还有大约70个该软件的其他用户没有出现此问题。

鉴于上述信息,我的问题是,为什么我们的存储过程停止处理?由于可能希望获得一个准确的答案,因此调试此错误的正确步骤是什么?DMV之一中可能有某些东西,例如dm_tran_locks,dm_exec_requests,dm_tran_database_transactions,dm_os_schedulers,dm_exec_sessions,尽管它们为我提供了一些信息,但我并没有以指向解决方案的方式来解释或理解输出。

以下是有问题的插入/选择:

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

链接到Exec Plan的XML(太大而无法嵌入)。


评论不作进一步讨论;此对话已转移至聊天
保罗·怀特9

Answers:


5

使用加密(如TDE)时,您不仅会在等待列表中看到ENCRYPTION_SCAN资源。

某些操作将对此资源进行共享锁定,以确保在操作过程中未对数据库进行加密。

用TDE加密用户数据库的那一刻,tempdb也将被加密(否则,当在temp db中使用User数据时,您将面临安全风险)。

因此,某些操作将对Tempdb中的ENCRYPTION_SCAN采取共享锁,以防止Tempdb进行加密。

这是两个示例:

批量插入

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上本地运行它。

接下来是开始批量插入循环。在循环运行时,打开第二个屏幕并开始运行sp_lock,直到看到DB_ID 2(这是Tempdb)中的ENCRYPTION_SCAN共享锁。

批量导入循环:

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

在第二个窗口中查看sp_lock的结果:

在此处输入图片说明

在TEMPDB中排序

使用相同的Temp表开始以下非常简单的循环:

SELECT * from #Import order by C
go 50

它将产生以下执行计划:

在此处输入图片说明

(请确保实际上已填充#Import,因为根据您何时停止上一个批量导入循环,它可能为空!)

同样,在第二个窗口中运行sp_lock,直到弹出ENCRYPTION_SCAN资源:

在此处输入图片说明

现在您知道了为什么出现此资源等待。可能这不是您的问题,这可能很好。我只是想指出导致ENCRYPTION_SCAN出现的其他原因。您的查询速度降低的原因可能是其他原因。我将把改进您的查询计划的工作留给本网站上的查询计划专家;-)但是,您是否也可以发布实际的执行计划而不只是估计的计划?


因此,ENCRYPTION_SCAN这有点像鲱鱼。这是一把S锁。因此理论上说,在OP看到的5个小时内,ENCRYPTION_SCAN 实际上只是忙于插入。不被它阻止吗?
Martin Smith

是的,我会这样认为。可能会很好地看到在运行期间使用扩展事件累积等待该spid的时间?确认用户实际上还在等待其他东西吗?困扰我的是“单个用户数据库是此行为的唯一实例…….70个其他未出现此问题的软件用户”。这可能是一个坏计划吗?(我没有看到任何参数查询的这个部分)我们需要实际的计划..
爱德华Dortland

@EdwardDortland我将尝试获取实际的查询计划。回复:马丁史密斯,我仍然感到困惑,为什么我看不到tempdb或我们的用户数据库的按年龄划分的顶级交易中的插入内容,尽管红鲱鱼会说明这一点。在复制数据库中,我重写了要使用的where子句或而不是isull的语句,并且在到目前为止的测试中(上周早些时候已部署),插入操作仅需几分钟即可完成,而没有ENCRYPTION_SCAN。
罗伯特·甘农2014年

@RobertGannon很高兴看到原始查询的实际计划与重新制定的计划之间的差异。
爱德华·多特兰2014年

2
一个相关的最近的一篇博客在这里确认所有信息blogs.msdn.microsoft.com/psssql/2016/04/19/...
马丁·史密斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.