【问题标题】:My SQL Server CLR function is very slow我的 SQL Server CLR 函数很慢
【发布时间】:2015-11-09 03:22:18
【问题描述】:

我在 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 Server 中创建了一个 CLR 函数,我尝试将其称为:

SELECT dbo.Decrypt(MyEncrypted, EncryptionKey)
FROM   MyTable

问题是,它花费了 太多时间。就像只有 1000 行一样,需要 1.5 分钟。如果我在没有 CLR 函数的情况下调用我的查询,则只需不到 1 秒。

我可以做些什么来提高 CLR 函数的性能?

【问题讨论】:

  • 可以使用sql server的加密吗?当你可以保存原始字节时,为什么要将它保存为字符串?
  • 会提高性能吗?
  • 也许吧。你必须测试它。
  • “MyEncrypted”和“EncryptionKey”列的数据大小是多少?在具有完全相同输入的 C# 控制台应用程序中运行该代码需要多长时间?
  • @jdweng OP 将此代码用作 CLR 函数,因此它在 sqlserver 上运行,在同一进程中但在单独的应用程序域中,不涉及防火墙...

标签: c# .net sql-server performance clr


【解决方案1】:

我已经在 VS2010 中使用性能分析器分析了您的 Decrypt 方法,运行了 100 次:

您可以看到Rfc2898DeriveBytes 实例的GetBytes 方法花费的时间最多。

我不确定您为什么有这些特定的加密/解密要求,但影响GetBytes 方法所用时间的一种方法是使用constructor 实例化Rfc2898DeriveBytes,该constructor 将迭代作为第三个参数。默认为 1000,我可以将其设置为 1。但强烈建议不要这样做

var pdb = new Rfc2898DeriveBytes(encryptionKey, salt, 10);  

对于EncryptDecrypt,此迭代确实需要相同,因此如果您想更改它,您必须解密\加密您的当前值。

另一个选项可能是缓存 IV 值,这似乎在this answer 中推荐。如果他们在那里谈论使用相同的密钥,我还不够专家,但如果这是一个选项,您也可以缓存对 GetBytes 的调用以获取密钥。

所有描述的更改都会影响您的数据加密方式和加密强度。在测试解决方案时考虑这两种影响。

【讨论】:

  • 减少密钥派生函数的迭代次数会产生密码学后果。不要为了提高性能而推荐它。
  • 好的。和缓存部分,将 IV 存储在表中并从配置文件/注册表@RemusRusanu 读取 KEY,这样您就不需要 GetBytes 调用解密?
  • ... 或使用 SQL Server 内置 ENCRYPTBYPASSPHRASE
  • @rene 感谢您的努力,但我们无法更改算法。
  • @RemusRusanu 数据库加密也不是一个选项。 :(
猜你喜欢
  • 1970-01-01
  • 2012-09-10
  • 2011-06-24
  • 1970-01-01
  • 2014-01-27
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 2016-01-25
相关资源
最近更新 更多