VBScript - Хранение SHA1 как числового или двоичного значения в SQL Server - PullRequest
3 голосов
/ 20 апреля 2011

В настоящее время я храню значение 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

Edit:
Благодаря ScottE и Google я смог заметно ускорить свои запросы. Вот небольшая информация о моем решении.
1) Я создал поле с именем SHA1Bin. Это поле типа двоичное (20).
2) Когда я вставляю новую запись, я использую хранимую процедуру. Поскольку я не слишком обеспокоен пространством, я сохраняю необработанное значение httpreferer и его двоичное значение SHA1 в той же таблице и той же строке. Моя хранимая процедура преобразует необработанное значение в двоичный файл SHA1 с помощью функции HashBytes (SQL Server 2008).
3) Моя функция SHA1 в VBScript остается такой же, как указано выше, но теперь я использую ее при поиске. Вот модифицированная версия функции 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 Ответ

1 голос
/ 21 апреля 2011

Я думаю, что вы относительно на правильном пути; однако есть несколько вещей, которые вы можете сделать, чтобы сделать это немного быстрее.

SHA1 Фон

Где бы вы ни читали, что SHA1 использовал бинарный код (20), он практически мертв. SHA1 - это 160-битное сообщение (20 байт), с которым мы обычно играем в необработанном формате - как вы уже знаете, поскольку ваша функция преобразует этот необработанный двоичный файл в строку.

Преобразование в ЧИСЛО

Таким образом, независимо от того, 20 байтов - это 20 байтов. Вы не можете преобразовать его во что-то другое, чтобы он работал быстрее для базы данных. Попытка преобразовать его в числовое будет безуспешной, поскольку вы получите ошибку арифметического переполнения (числовое имеет место только для 17 байтов).

Как сделать лучше

У вас есть половина сражения. Вы можете сохранить данные как символьный тип данных, если с ними легче работать в VBScript. Кроме того, вы можете сохранить его как двоичный файл (20); это подход, который я использую для своих проектов хранилищ данных. Если вы собираетесь сохранить его как строку, сделайте его CHAR (20), а не CHAR (40). Тип данных CHAR хранит указанное количество байтов, даже если половина из них пуста (что для вас почти так). Единственное «пойманное» в этом то, что ваша функция будет рендерить «0x ...» в начале строки, которая технически не является частью значения, но необходима для указания того, что значение является двоичным при построении Оператор SQL Таким образом, вы можете использовать CHAR (22) или просто выполнить конкатенацию, где это необходимо. В любом случае, уменьшая количество символов в определении поля, SQL выполняет меньше операций чтения, чтобы получить ваши данные, что ускорит процесс. Другим альтернативным типом данных может быть VARCHAR, который урезает пробелы в конце строки (опять же, меньшее число операций чтения приводит к успешному запросу).

Кроме того, индексируйте его так же, как вы сделали. Если вы еще этого не сделали, создайте индекс в столбце SHA1 и включите в индекс httprefererid, ваш запрос будет использовать только индекс для выбора и будет самым быстрым, каким он может быть, поскольку необходимы только элементы данных будет прочитано Это называется индекс покрытия (потому что он охватывает ваш фильтр плюс выбранные столбцы). Этот индекс будет выглядеть примерно так:

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

Надеюсь, это поможет!

...