SQL Server 2014上的DECRYPTBYKEY比SQL Server 2012慢

anc*_*ncs 9 sql-server encryption database-performance sql-server-2012 sql-server-2014

几年来,我们一直在某些SQL Server 2012实例上使用对称密钥进行加密/解密.我们最近安装了一些SQL Server 2014的新实例,并遇到了解密SQL Server 2014安装数据的一些性能问题.

考虑一个看起来像这样的表:

CREATE TABLE [dbo].[tblCertTest](
[article_id_enc] [varbinary](100) NOT NULL,
[article_id] [int] NULL
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

和键和证书创建如下:

CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'Passwrrrrd12'

CREATE CERTIFICATE MyCertificateName
WITH SUBJECT = 'A label for this certificate'

CREATE SYMMETRIC KEY MySymmetricKeyName WITH
IDENTITY_VALUE = 'a fairly secure name',
ALGORITHM = AES_256,
KEY_SOURCE = 'a very secure strong password or phrase'
ENCRYPTION BY CERTIFICATE MyCertificateName;
Run Code Online (Sandbox Code Playgroud)

我们的数据集大约有90000行,article_id是一个5位数字.稍微简化一下,article_id_enc使用以下命令加密:

update tblCertTest set article_id_enc = ENCRYPTBYKEY(KEY_GUID('MySymmetricKeyName'),convert(varbinary(100), article_id))
Run Code Online (Sandbox Code Playgroud)

我们已经应用了所有可用的修补程序,我们尝试了不同的SQL Server 2012和SQL Server 2014实例,使用不同的设置,如ssd磁盘,ram磁盘等.

我们在SQL Server和远程上本地尝试了查询.

所有服务器上的执行计划和索引都是相同的.

在任何SQL Server 2012服务器上,此SELECT语句大约需要50 ms,包括简单的开发计算机.在任何SQL Server 2014服务器(包括非常强大的服务器)上,查询至少需要1500毫秒.

OPEN SYMMETRIC KEY MySymmetricKeyName
DECRYPTION BY CERTIFICATE MyCertificateName

SELECT CONVERT(int, DecryptByKey(article_id_enc))
FROM dbo.tblCertTest
Run Code Online (Sandbox Code Playgroud)

有关查询在SQL Server 2014上执行如此糟糕的原因的任何建议?改变了什么?

Mar*_*ith 10

编辑:我刚刚注意到有一篇知识库文章FIX:使用DECRYPTBYKEY函数的查询在SQL Server 2014中需要很长时间,但我安装了它,它似乎没有改变下面的原始结论.

在运行Windows 10的四核(Intel Core i5-2320)X64台式机上运行SQL Server 2012(11.0.5343.0)和2014(RTM)中的以下代码.

OPEN SYMMETRIC KEY MySymmetricKeyName DECRYPTION BY CERTIFICATE MyCertificateName;

DECLARE @B VARBINARY(100);

WITH t
     AS (SELECT ROW_NUMBER() OVER (ORDER BY @@SPID) AS article_id
         FROM   sys.all_objects o1,
                sys.all_objects o2,
                sys.all_objects o3,
                sys.all_objects o4)
SELECT @B = ENCRYPTBYKEY(KEY_GUID('MySymmetricKeyName'), CONVERT(VARBINARY(100), article_id))
FROM   t 
Run Code Online (Sandbox Code Playgroud)

并在Process Explorer中查看它

2012

在此输入图像描述

2014

在此输入图像描述

有两件事情变得很明显.

2012版本使用的CPU较少,并且最大限度地利用了单个核心.2014版本使用的不仅仅是一个核心,而且内核模式活动明显更多(红色)

Process Explorer"threads"窗口显示

2012

在此输入图像描述

单个线程正在垄断调度程序.

2014

在此输入图像描述

这里的工作由两个线程执行(线程3212正在运行空闲任务sqldk.dll!SOS_Scheduler::Idle).

跟踪2014进程表明SQL Server和这两个线程遇到了很多上下文切换(跟踪时间不同于之前的屏幕截图,因此不同的线程ID)

在此输入图像描述

使用Windows Performance Toolkit跟踪这两个进程显示了在不同模块中花费的时间的一些显着差异

2012

在此输入图像描述

2014

在此输入图像描述

我不确定为什么2014版本在这个视图中报告25%的CPU而在其他视图中报告30%但是无论如何很明显在ntoskrnl.exe中花费的时间在版本之间显着增加,现在花费了60%的时间在该模块的代码中.执行加密所花费的时间当然相应地下降.

并附加了VS代码分析器的2012版本看起来像这样与2014年类似这样.

所以看起来好像2014有额外的逻辑来阻止调度程序占用,并且它会更频繁地关闭,如下面的附加项所示.

在此输入图像描述

(与2012年相比)

在此输入图像描述

在两个版本中尝试以下操作以执行操作100万次...

SET STATISTICS TIME ON;

DECLARE @B VARBINARY(100);

OPEN SYMMETRIC KEY MySymmetricKeyName DECRYPTION BY CERTIFICATE MyCertificateName;

DBCC SQLPERF("sys.dm_os_wait_stats", CLEAR);

WITH t
     AS (SELECT ROW_NUMBER() OVER (ORDER BY @@SPID) AS article_id
         FROM   master..spt_values v1,
                master..spt_values v2
         WHERE  v1.type = 'P'
                AND v2.type = 'P'
                AND v1.number BETWEEN 1 AND 1000
                AND v2.number BETWEEN 1 AND 1000)
SELECT @B = ENCRYPTBYKEY(KEY_GUID('MySymmetricKeyName'), CONVERT(VARBINARY(100), article_id))
FROM   t

SELECT *
FROM   sys.dm_os_wait_stats
WHERE  wait_type IN ( 'PREEMPTIVE_OS_CRYPTOPS', 'SOS_SCHEDULER_YIELD' ); 
Run Code Online (Sandbox Code Playgroud)

2012(CPU时间= 2344 ms,经过时间= 2383 ms.)

在此输入图像描述

可以清楚地看到,虽然PREEMPTIVE_OS_CRYPTOPS等待类型确实存在于2012年,但在这种情况下不使用.

相反,它看起来好像查询或多或少地垄断了调度程序(尽管仍然在其4毫秒量子结束时自愿屈服 - 4*597 = 2388)

2014(CPU时间= 8188 ms,经过时间= 10569 ms.)

在此输入图像描述

而对于2014年,ENCRYPTBYKEY函数的每次调用都会遇到此等待类型,在这种情况下,它(与上下文切换相结合)为总体运行时间增加了8.2秒.

下面突出显示了一些更耗时的内核调用的调用堆栈.

在此输入图像描述

我还尝试了另外一个实验

2014年 - SQL Server与单CPU密切相关

(CPU时间= 4500毫秒,经过时间= 6648毫秒.)

在此输入图像描述

这里的时间安排介于2012年的表现和2014年非关联性能之间,其中代码跨多个不同的核心执行.