我们几年来一直在某些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]
按键和证书创建如下:
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;
我们的数据集大约有90000行,article_id是一个5位数字。稍微简化一下,article_id_enc使用以下命令加密:
update tblCertTest set article_id_enc = ENCRYPTBYKEY(KEY_GUID('MySymmetricKeyName'),convert(varbinary(100), article_id))
我们已经应用了所有可用的修补程序,我们尝试了不同的SQL Server 2012和SQL Server 2014实例,使用不同的设置,如ssd磁盘,ram磁盘等。
我们在SQL Server和远程上尝试了本地查询。
所有服务器上的执行计划和索引都是相同的。
此SELECT语句在任何SQL Server 2012服务器上大约需要50毫秒,包括简单的开发计算机。在任何SQL Server 2014服务器(包括非常强大的服务器)上,查询至少需要1500毫秒。
OPEN SYMMETRIC KEY MySymmetricKeyName
DECRYPTION BY CERTIFICATE MyCertificateName
SELECT CONVERT(int, DecryptByKey(article_id_enc))
FROM dbo.tblCertTest
有关查询在SQL Server 2014上执行如此糟糕的原因的任何建议吗?有什么改变?
答案 0 :(得分:9)
编辑:我刚刚注意到有一篇知识库文章FIX: A query that uses the DECRYPTBYKEY function takes a long time in 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
在Process Explorer中查看它
有两件事情会立即显现出来。
2012版本使用的CPU较少,并且最大限度地利用了单个核心。 2014版本使用的不仅仅是一个核心,并且具有更多的内核模式活动(红色)
Process Explorer“threads”窗口显示
单个线程正在独占调度程序。
这里的工作由两个线程执行(线程3212正在运行空闲任务sqldk.dll!SOS_Scheduler::Idle
)。
跟踪2014进程显示SQL Server和这两个线程遇到大量上下文切换(跟踪时间不同于之前的屏幕截图,因此不同的线程ID)
使用Windows Performance Toolkit跟踪这两个进程显示在不同模块中花费的时间存在一些显着差异
我目前还不确定为什么2014版本会在此视图中报告25%的CPU而在其他视图中报告30%但是无论如何很明显ntoskrnl.exe花费的时间在版本之间显着增加,现在60%时间花在该模块的代码中。执行加密所花费的时间当然会相应减少。
将2012版本的VS代码分析器附加到this和2014 this。
所以看起来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' );
可以清楚地看到,尽管2012年存在PREEMPTIVE_OS_CRYPTOPS
等待类型,但在这种情况下不使用它。
相反,它看起来好像查询或多或少地垄断了调度程序(虽然在4毫秒量子结束时仍然自愿屈服 - 4 * 597 = 2388)
2014年,ENCRYPTBYKEY
函数的每次调用都会遇到此等待类型,在这种情况下,它(与上下文切换相结合)在整个已用时间上增加了8.2秒。
下面突出显示了一些更耗时的内核调用的调用堆栈。
我还尝试了另一个实验
这里的时间安排介于2012年业绩和2014年非关联性能之间,代码在多个不同核心上执行。