DECRYPTBYKEY медленнее в SQL Server 2014, чем в SQL Server 2012.

Мы использовали симметричные ключи для шифрования/дешифрования на некоторых экземплярах 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-диски, оперативные диски и т. д.

Мы попробовали запрос локально на SQL Server и удаленно.

Планы выполнения и индексы одинаковы на всех серверах.

Этот оператор SELECT занимает около 50 мс на любом сервере SQL Server 2012, включая простые компьютеры для разработки. На любом сервере 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? Что изменилось?




Ответы (1)


Изменить: я только что заметил, что есть статья базы знаний ИСПРАВЛЕНИЕ: запрос, использующий функцию DECRYPTBYKEY занимает много времени в SQL Server 2014, но он у меня установлен, и, похоже, это не меняет первоначальных выводов, приведенных ниже.

Выполнение следующего кода в SQL Server 2012 (11.0.5343.0) и 2014 (окончательная первоначальная версия) на четырехъядерном (Intel Core i5-2320) настольном компьютере X64 под управлением Windows 10.

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

введите здесь описание изображения

2014

введите здесь описание изображения

Сразу становятся очевидными две вещи.

Версия 2012 года использует меньше ЦП и максимально использует одно ядро. Версия 2014 года использует более одного ядра и значительно активнее работает в режиме ядра (красный).

Окно потоков Process Explorer показывает

2012

введите здесь описание изображения

Один поток монополизирует планировщик.

2014

введите здесь описание изображения

Здесь работа выполняется двумя потоками (поток 3212 выполняет задачу бездействия sqldk.dll!SOS_Scheduler::Idle).

Отслеживание процесса 2014 года показывает, что SQL Server и эти два потока сталкиваются с большим количеством переключений контекста (трассировка сделана в другое время, чем на предыдущем снимке экрана, поэтому идентификаторы потоков различаются)

введите здесь описание изображения

Отслеживание двух процессов с помощью Windows Performance Toolkit показывает некоторые существенные различия во времени, затраченном на разные модули.

2012

введите здесь описание изображения

2014

введите здесь описание изображения

На данный момент я не уверен, почему версия 2014 сообщает о 25% ЦП в этом представлении по сравнению с 30% в других, но в любом случае очевидно, что время, затрачиваемое на ntoskrnl.exe, резко увеличилось между версиями, и теперь тратится 60% времени. в коде в этом модуле. Время, затрачиваемое на шифрование, конечно, соответственно сократилось.

При подключении профилировщика кода VS версия 2012 года выглядит как этот, а версия 2014 – как это.

Таким образом, похоже, что в 2014 году есть дополнительная логика, чтобы остановить перегрузку планировщика, и он отключается чаще, как показано дополнительными элементами ниже.

введите здесь описание изображения

(по сравнению с 2012 г.)

введите здесь описание изображения

Попытка в обеих версиях выполнить операцию 1 миллион раз...

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 (время процессора = 2344 мс, прошедшее время = 2383 мс.)

введите здесь описание изображения

Хорошо видно, что хотя тип ожидания PREEMPTIVE_OS_CRYPTOPS существует в 2012 году, в данном случае он не используется.

Вместо этого выглядит так, как будто запрос более или менее монополизирует планировщик (хотя все еще добровольно уступает в конце своего кванта 4 мс - 4 * 597 = 2388)

2014 (время процессора = 8188 мс, прошедшее время = 10569 мс.)

введите здесь описание изображения

Принимая во внимание, что в 2014 году каждый вызов функции ENCRYPTBYKEY сталкивается с этим типом ожидания, и в этом случае он (в сочетании с переключением контекста) добавил 8,2 секунды к общему истекшему времени.

Стеки вызовов для некоторых наиболее трудоемких вызовов ядра выделены ниже.

введите здесь описание изображения

Я также попробовал еще один эксперимент

2014 — SQL Server привязан к одному ЦП

(время ЦП = 4500 мс, прошедшее время = 6648 мс.)

введите здесь описание изображения

Время здесь находилось где-то между производительностью 2012 года и производительностью без аффинитиза 2014 года, когда код выполнялся на нескольких разных ядрах.

person Martin Smith    schedule 17.03.2015