VBScript - 在 SQL Server 中将 SHA1 存储为数字或二进制值

Posted

技术标签:

【中文标题】VBScript - 在 SQL Server 中将 SHA1 存储为数字或二进制值【英文标题】:VBScript - Storing SHA1 as Numeric or Binary Value in SQL Server 【发布时间】:2011-04-20 16:20:36 【问题描述】:

我目前在 SQL Server 中将我的 SHA1 值存储为 char(40)。我的印象是,我可以通过将此字段更改为数值来提高查找速度。但是,我不确定在 SQL Server 中使用什么字段/数据类型来存储它以及如何在 VBScript 中转换它。我应该使用数字还是小数?我需要使用多少位?

我在某处读到建议使用 Binary(20)。但是,在 VBScript 中使用二进制值似乎并不容易,所以我假设我最好使用数值来代替。

目前这是我的 SHA1 函数。我将它返回的字符串值存储在数据库中的 char(40) 字段中,并使用下面的第二段代码执行查找。

Private Function SHA1(s)
    Dim asc, enc, bytes, outstr, pos
    Set asc = CreateObject("System.Text.UTF8Encoding")
    Set enc = CreateObject("System.Security.Cryptography.SHA1CryptoServiceProvider")
    'Convert the string to a byte array and hash it
    bytes = asc.GetBytes_4(s) 'This is how you use .Net overloaded methods in VBScript
    bytes = enc.ComputeHash_2((bytes))
    outstr = ""
    'Convert the byte array to a hex string
    For pos = 1 To Lenb(bytes)
        outstr = outstr & LCase(Right("0" & Hex(Ascb(Midb(bytes, pos, 1))), 2))
    Next
    SHA1 = outstr
    Set asc = Nothing
    Set enc = Nothing
End Function

这是我的查找函数。它已经运行得很快,但我正在寻找任何可以优化我的代码的方法。如果我确实使用二进制来存储数据,我在查找时也将不得不使用它。我想我可能会使用存储过程,它允许我使用 SQL Server 函数来回转换。也许那会是一条更好的路线。请指教。

Function GetHTTPRefererIDBySHA1(s)
    Dim r
    Set r = Server.CreateObject("ADODB.Recordset")      
    r.open "SELECT httprefererid FROM httpreferer " & _
            "WHERE sha1 = '" & s & "'", con, adOpenForwardOnly, adLockReadOnly
    If Not (r.eof and r.bof) then
        GetHTTPRefererIDBySHA1 = r("httprefererid")
    End If
    r.close
    set r = nothing
End Function

编辑: 感谢 ScottE 和 Google,我能够显着加快查询速度。这是有关我的解决方案的一些信息。 1) 我创建了一个名为 SHA1Bin 的字段。它是二进制 (20) 类型的字段。 2)当我插入新记录时,我使用存储过程。因为我不太关心空间,所以我将原始 httpreferer 值和它的 SHA1 二进制值保存在同一个表和同一行中。我的存储过程使用 HashBytes 函数 (SQL Server 2008) 将原始值转换为 SHA1 二进制文件。 3) 我在 VBScript 中的 SHA1 函数与上面相同,但我现在在查找时使用它。这是 GetReferer 函数的修改版本:

Function GetHTTPRefererIDBySHA1(s)
    Dim r
    Set r = Server.CreateObject("ADODB.Recordset")      
    r.open "SELECT httprefererid FROM httpreferer WHERE " & _
            "sha1bin = CONVERT(binary(20), 0x" & SHA1(s) & ")", _
            tcon, adOpenForwardOnly, adLockReadOnly

    If Not (r.eof and r.bof) then
        GetHTTPRefererIDBySHA1 = r("httprefererid")
    Else
        '//Insert new record code intentionally omitted
    End If
    r.close
    set r = nothing
End Function

【问题讨论】:

愚蠢的问题 - 你索引 sha1 列了吗? 是的,我已经将它编入索引。这并不是说它的表现明显缓慢。只是我假设通过使用更高效的存储/查找,它可以表现得更好。 【参考方案1】:

我认为您相对正确;但是,您可以采取一些措施来加快速度。

SHA1 背景

无论您在哪里读到SHA1 使用二进制(20)几乎都是死的。 SHA1 是一个 160 位消息(20 字节),我们通常使用它的原始格式 - 正如您已经知道的那样,因为您的函数将原始二进制文件转换为字符串。

转换为数字

所以不管怎样,20 个字节就是 20 个字节。您不能将其转换为其他内容以使其对数据库执行得更快。尝试将其转换为数字会失败,因为您会收到算术溢出错误(数字只有 17 个字节的空间)。

如何让它变得更好

你已经完成了一半的战斗。如果在 VBScript 中更容易使用,您可以将数据保留为字符数据类型。或者,您可以将其存储为 BINARY(20);这是我为我的数据仓库项目采用的方法。如果要将其保留为字符串,请将其设为 CHAR(20) 而不是 CHAR(40)。 CHAR 数据类型存储指定的字节数,即使其中一半是空的(您几乎就是这种情况)。其中的一个“陷阱”是您的函数将喜欢在字符串的前面呈现一个“0x ...”,这在技术上不是值的一部分,但在构造您的值时有必要表明该值是二进制的SQL 语句。因此,您可以使用 CHAR(22) 或仅在必要时进行连接。在任何一种情况下,通过减少字段定义中的字符数,SQL 执行更少的读取来获取您的数据,这将加快速度。另一种数据类型替代方案是 VARCHAR,它会修剪字符串末尾的空格(同样,更少的读取会带来快乐的查询)。

除此之外,就像您所做的那样对其进行索引。如果您还没有这样做,请在您的 SHA1 列上创建一个索引并将 httprefererid 包含在索引中,您的查询将仅使用索引进行选择,并且将是最快的,因为它只需要必要的数据元素将被阅读。这称为covering index(因为它涵盖了您的过滤器和选定的列)。该索引看起来像:

create index ix_httpreferer_sha1 on dbo.httpreferer (sha1) include (httprefererid);

希望有帮助!

【讨论】:

我确实有一个问题。你提到我应该使用 CHAR(20) 而不是 CHAR(40)。如果我理解正确,我的 SHA1 函数实际上是返回 40 个字符的 ascii/十六进制。为了将它减少到只有 20 个字节,我将不得不使用其他格式。我可以将我的 20 字节变量 bytes 转换为这 20 个字节的 ascii 表示吗?如果理解正确的话,其中一个问题是任何出现的 chr(0) 都会导致我的字符串变量被终止。 我有但没有尝试过的一个想法是将 20 字节数组作为二进制 (20) 直接存储到数据库中,但我不确定如何对其进行查询.

以上是关于VBScript - 在 SQL Server 中将 SHA1 存储为数字或二进制值的主要内容,如果未能解决你的问题,请参考以下文章

按钮单击 asp 以删除 SQL 服务器中的行 - 经典 asp 和 vbscript

尝试使用 vbscript 显示 SQL 数据库中的数据

ADODB连接不会连接到sql server Express

什么是备份 SQL Server 数据库的简单命令行程序或脚本?

连接到SQL Server时OLEDB / ODBC驱动程序之间有什么区别?

如何在VBScript中使用ADODB结果集? [关闭]