sql-server - SQL Server 2014 上的 DECRYPTBYKEY 比 SQL Server 2012 慢

标签 sql-server encryption sql-server-2012 database-performance sql-server-2014

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

考虑一个如下所示的表格:

CREATE TABLE [dbo].[tblCertTest](
[article_id_enc] [varbinary](100) NOT NULL,
[article_id] [int] NULL
) ON [PRIMARY]

key 和证书创建如下:

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 上表现如此糟糕,有什么建议吗?发生了什么变化?

最佳答案

Edit: I just noticed that there is a KB article FIX: A query that uses the DECRYPTBYKEY function takes a long time in SQL Server 2014 but I have that installed and it doesn't appear to change the original conclusions below.

在运行 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

enter image description here

2014

enter image description here

有两件事立即变得显而易见。

2012 版本使用的 CPU 较少,并且最大限度地利用了单核。 2014 版本使用多个内核,并且内核模式事件显着增加(红色)

Process Explorer“线程”窗口显示

2012

enter image description here

单个线程独占调度程序。

2014

enter image description here

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

跟踪 2014 年进程显示 SQL Server 和这两个线程遇到了大量上下文切换(跟踪的时间与之前的屏幕截图不同,因此线程 ID 不同)

enter image description here

使用 Windows Performance Toolkit 跟踪两个进程显示不同模块所花费的时间存在显着差异

2012

enter image description here

2014

enter image description here

目前我不确定为什么 2014 版本在此 View 中报告 25% CPU,而在其他 View 中报告 30%,但无论如何,很明显,ntoskrnl.exe 花费的时间在不同版本之间急剧增加,现在为 60%时间花在该模块的代码上。执行加密所花费的时间当然也相应减少了。

附加 VS 代码分析器,2012 版本看起来像 this和 2014 年类似 this .

因此,2014 年似乎有额外的逻辑来阻止这种占用调度程序的情况,并且它会更频繁地关闭,如下面的附加项目所突出显示的那样。

enter image description here

(与2012年相比)

enter image description here

在两个版本中尝试以下操作来执行操作 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(CPU 时间 = 2344 毫秒,运行时间 = 2383 毫秒。)

enter image description here

可以清楚地看出,虽然 PREEMPTIVE_OS_CRYPTOPS 等待类型在 2012 年确实存在,但在本例中并未使用。

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

2014(CPU 时间 = 8188 毫秒,运行时间 = 10569 毫秒。)

enter image description here

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

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

enter image description here

我还尝试了另一个实验

2014 - SQL Server 关联到单 CPU

(CPU 时间 = 4500 毫秒,运行时间 = 6648 毫秒。)

enter image description here

这里的时间介于 2012 年性能和 2014 年非关联性能之间,其中代码跨多个不同的内核执行。

关于sql-server - SQL Server 2014 上的 DECRYPTBYKEY 比 SQL Server 2012 慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29105290/

相关文章:

sql-server - Uniqueidentifier vs. IDENTITY vs. Material Code——哪个是主键的最佳选择?

sql - 在 SQL SERVER 光标中从顶部继续?

sql-server - SQL数据库触发器线程安全吗?

SQL 备份版本与此服务器不兼容

mysql - 来自中间人的攻击,如何解决?

sql - 动态 SQL "USE [DB]"不起作用

sql - 尝试将 SQL Server 2008 (SP2) 升级到 SQL Server 2012 时出错 : There was a failure to calculate the applicability of setting LICENSEPATH

sql-server - 在sql函数中使用表名作为参数

encryption - 当加密不是 block 大小的偶数倍的数据时,我必须发送完整的最后一个 block 吗?

javascript - 保护 Websocket 的安全