Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Мы продолжаем наш рассказ о новой, оптимизированной для исполнения в оперативной памяти, СУБД SQL 2014 (In-Memory Database).
В предыдущем блоге мы рассказали об основах физического размещения данных на диске и в оперативной памяти (https://blogs.technet.com/b/sqlruteam/archive/2014/03/28/sql2014_5f00_memory_5f00_optimized_5f00_rdbms_5f00_overview_5f00_physical_5f00_structure.aspx).
Текущий блог будет посвящен Hash-индексам, лежащим в основе хранения и доступа к данным в этой СУБД.
Основы хеширования.
В начале обратимся к Википедии, для того, что бы понять, что такое хеширование. (https://ru.wikipedia.org/wiki/%D0%A5%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5).
"Хеширование (иногда «хэширование» , англ. hashing) — преобразование по детерминированному алгоритму входного массива данных произвольной длины в выходную битовую строку фиксированной длины. Такие преобразования также называются хеш-функциями или функциями свёртки , а их результаты называют хешем , хеш-кодом или сводкой сообщения (англ. message digest).
В общем случае однозначного соответствия между исходными данными и хеш-кодом нет в силу того, что количество значений хеш-функций меньше, чем вариантов входного массива; существует множество массивов с разным содержимым, но дающих одинаковые хеш-коды, эта ситуация называется хеш-коллизией. Вероятность возникновения коллизий играет немаловажную роль в оценке качества хеш-функций."
Хорошая хеш-функция должна удовлетворять двум свойствам:
-
- Быстро вычисляться;
- Минимизировать количество коллизий
Существует большое количество алгоритмов хеширования, как интернациональных, так и принятых только в одной стране. Например интернациональные алгоритмы пришедшие в Россию вместе с продуктами Microsoft: MD5, SHA1, SHA256, SHA384. Алгоритмы принятые в России ГОСТ Р 34.11-94, ГОСТ Р 34.11-2012.
Hash-индексы
В отличии от стандартной СУБД (Disk based) где страницы, принадлежащие одной таблице, должны быть связаны при помощи IAM, строки в таблицах In-Memory database обязательно должны быть связаны при помощи Hash-индексов. Таким образом In-Memory optimized таблицы должны иметь хотя бы один Hash-индекс.
Hash-индексы используют детерминистическую функцию для построения hash-значения. Т.е. эта функция при подаче на вход одинаковых значений гарантировано сгенерирует один и тот же hash.
Ниже показан пример hash-индекса, который строится на основе количества символов в строке. (Данный пример показан для простоты и не используется в реальных системах.) Hash-индекс построен на основе Имени (поле Name). Если строки, на основе которых строится индекс уникальны, то каждый hash-индекс будет ссылаться только на одну строку, если строки не уникальны, или размер hash-таблицы мал для отображения всех строк (размер таблицы меньше чем кардинальность набора данных), то один hash-индекс указывает на цепочку строк.
При добавлении строки, порождающей тот же hash она будет связана в цепочку, как показано на рисунке ниже.
Размер hash-таблицы указывается при создании таблицы. Он указывается в количестве значений hash-ключей. Указав чрезмерный размер hash-таблицы (значительно больше чем планируемое количество уникальных значений в таблице) вы резервируете оперативную память, которая не может быть использована и будет потеряна для системы. Однако, указав недостаточный размер hash-таблицы, вы получите ситуацию показанную на рисунке выше, при которой сервер будет вынужден двигаться по цепочке ссылок, ища нужную запись.
Что произойдет, если мы будем вставлять строку с именем содержащем 3.5 буквы (хотя это невозможно, но для примера представьте себе). При вставке такой строки SQL Server должен размещать ее либо в цепочке строк соответствующий значению 3, либо значению 4. Т.е. имеет место hash-коллизия. Как SQL Server поступает в этом случае? В таком случае он будет балансировать систему, что бы длины цепочек были приблизительно одинаковы. Т.е. одна строка может попасть в цепочку строк, соответствующую значению 3, а вторая, значению 4.
Для балансировки используется Poison-алгоритм. Суть которого состоит в том, что если вы пытаетесь распределить N-значений ключей среди M-значений hash-функций, то приблизительно 1/3 ячеек будет пустой, приблизительно 1/3 ячеек будет содержать по одному значению, приблизительно 1/3 ячеек будет содержать по два значения, и малая часть будет содержать два и более значения.
Таким образом наличие hash-коллизии приводит к увеличению операций чтения, которые должна сделать система для выборки строк, поскольку будут считываться строки из нескольких hash-ключей.
Как изменится структура таблицы если добавить еще один hash-индекс?
На рисунке показано добавление нового индекса по полю город. Здесь также показана ситуация, когда произошло обновление поля City в строке с полем Name "Susan". Обратите внимание на появление новой строки с временной меткой "90, OO". Эта строка с момента времени 90 становиться актуальной, а предыдущая с меткой времени "70, 90" не актуальной, информация о ней помещается в Delta-файл и со временем она будет удалена. Последняя строка в цепочке будет содержать NULL в поле индекса. Если в данной ситуации вы выполните запрос SELECT * FROM t1 WHERE City='Bogota', то SQL Server будет вынужден считать две строки: строку "Lisbon" и строку "Bogota", но возвращена будет только одна, соответствующая критерию поиска. Такое поведение обусловлено наличием hash коллизии, поскольку оба названия городов содержат по 6 букв (мы договорились, что для упрощения мы будем в качестве hash-функции использовать количество букв в поле).
Необходимо помнить о том, что если вы создаете композитный (состоящий из нескольких столбцов) hash-индекс, то при выполнении поиска, вам необходимо указать (в качестве критерия поиска) все столбцы, входящие в этот индекс, поскольку поиск по частичному hash-значению невозможен.
Например. Если вы построили hash-индекс по LastName, FirstName, MiddleName, то при выполнении запроса вам необходимо указать все три значения в операторе WHERE. Еще одна проблема (особенность) hash-индексов, с их помощью невозможен поиск по диапазону значений.
Для выполнения поиска по диапазону значений в In-Memory database SQL 2014 используются специальные Bw-tree индексы, которые внешне схожи со стандартными B-tree индексами классической СУБД, но отличаются по ряду свойств. Но о них пойдет рассказ в нашем следующем блоге.
Александр Каленик, Senior Premier Field Engineer (PFE), MSFT (Russia)


