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

时间:2011-04-20 16:20:36

标签: sql-server vbscript asp-classic sha1

我目前将我的SHA1值存储在SQL Server中作为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

1 个答案:

答案 0 :(得分:1)

我认为你是相对正确的;但是,你可以采取一些措施来加快这一点。

SHA1背景

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

转换为NUMERIC

所以无论如何,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);

希望有所帮助!