我的 SQL 服务器 CLR 功能很慢
My SQL Server CLR function is very slow
我在 C# 中创建了两个方法:
public static string Encrypt(string clearText, string encryptionKey)
{
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
using (Aes encryptor = Aes.Create())
{
var pdb = new Rfc2898DeriveBytes(encryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
clearText = Convert.ToBase64String(ms.ToArray());
}
}
return clearText;
}
public static string Decrypt(string cipherText, string encryptionKey)
{
try
{
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create())
{
var pdb = new Rfc2898DeriveBytes(encryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
cipherText = Encoding.Unicode.GetString(ms.ToArray());
}
}
}
catch (Exception)
{
}
return cipherText;
}
按照 This Link 中给出的步骤,我在 SQL 服务器中创建了一个 CLR 函数,我试图这样调用它:
SELECT dbo.Decrypt(MyEncrypted, EncryptionKey)
FROM MyTable
问题是,它花费了太多时间。就像只有 1000 行一样,花了 1.5 分钟。如果我在没有 CLR 函数的情况下调用我的查询,它花费的时间不到 1 秒。
我可以做些什么来提高 CLR 函数的性能吗?
我已经用 VS2010 中的性能分析器分析了你的 Decrypt
方法 运行 100 次:
如您所见,GetBytes
method of the Rfc2898DeriveBytes
实例花费的时间最多。
我不确定您为什么有这些特定的 encryption/decryption 要求,但影响 GetBytes
方法所用时间的一种方法是使用 [=21= 实例化 Rfc2898DeriveBytes
] 以迭代作为第三个参数。默认值为 1000,我可以将其设置为低至 1。但强烈建议反对
var pdb = new Rfc2898DeriveBytes(encryptionKey, salt, 10);
对于 Encrypt
和 Decrypt
,此迭代确实需要相同,因此如果您想更改它,则必须 Decrypt\Encrypt 当前值。
另一种选择可能是像 this answer 中推荐的那样缓存 IV 值。如果他们在那里谈论使用相同的密钥,我还不够专家,但如果这是一个选项,您也可以缓存对 GetBytes
的调用以获取密钥。
所有描述的更改都会影响您的数据加密方式和加密强度。在测试解决方案时考虑这两种影响。
我在 C# 中创建了两个方法:
public static string Encrypt(string clearText, string encryptionKey)
{
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
using (Aes encryptor = Aes.Create())
{
var pdb = new Rfc2898DeriveBytes(encryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
clearText = Convert.ToBase64String(ms.ToArray());
}
}
return clearText;
}
public static string Decrypt(string cipherText, string encryptionKey)
{
try
{
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create())
{
var pdb = new Rfc2898DeriveBytes(encryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
cipherText = Encoding.Unicode.GetString(ms.ToArray());
}
}
}
catch (Exception)
{
}
return cipherText;
}
按照 This Link 中给出的步骤,我在 SQL 服务器中创建了一个 CLR 函数,我试图这样调用它:
SELECT dbo.Decrypt(MyEncrypted, EncryptionKey)
FROM MyTable
问题是,它花费了太多时间。就像只有 1000 行一样,花了 1.5 分钟。如果我在没有 CLR 函数的情况下调用我的查询,它花费的时间不到 1 秒。
我可以做些什么来提高 CLR 函数的性能吗?
我已经用 VS2010 中的性能分析器分析了你的 Decrypt
方法 运行 100 次:
如您所见,GetBytes
method of the Rfc2898DeriveBytes
实例花费的时间最多。
我不确定您为什么有这些特定的 encryption/decryption 要求,但影响 GetBytes
方法所用时间的一种方法是使用 [=21= 实例化 Rfc2898DeriveBytes
] 以迭代作为第三个参数。默认值为 1000,我可以将其设置为低至 1。但强烈建议反对
var pdb = new Rfc2898DeriveBytes(encryptionKey, salt, 10);
对于 Encrypt
和 Decrypt
,此迭代确实需要相同,因此如果您想更改它,则必须 Decrypt\Encrypt 当前值。
另一种选择可能是像 this answer 中推荐的那样缓存 IV 值。如果他们在那里谈论使用相同的密钥,我还不够专家,但如果这是一个选项,您也可以缓存对 GetBytes
的调用以获取密钥。
所有描述的更改都会影响您的数据加密方式和加密强度。在测试解决方案时考虑这两种影响。