Модель данных | Tarantool
Документация на русском языке
поддерживается сообществом
Модель данных

Модель данных

В этом разделе описывается то, как в Tarantool организовано хранение данных и какие операции с данными он поддерживает.

Если вы пробовали создать базу данных, как предлагается в упражнениях в «Руководстве для начинающих», то ваша тестовая база данных выглядит следующим образом:

../../../_images/data_model.png

Спейс – с именем „tester“ в нашем примере – это контейнер.

Когда Tarantool используется для хранения данных, всегда существует хотя бы один спейс. У каждого спейса есть уникальное имя, указанное пользователем. Кроме того, пользователь может указать уникальный числовой идентификатор, но обычно Tarantool назначает его автоматически. Наконец, в спейсе всегда есть движок: memtx (по умолчанию) – in-memory движок, быстрый, но ограниченный в размере, или vinyl – дисковый движок для огромного количества данных.

Спейс – это контейнер для кортежей. Для работы ему необходим первичный индекс. Также возможно использование вторичных индексов.

Кортеж играет такую же роль, как “строка” или “запись”, а компоненты кортежа (которые мы называем “полями”) играют такую же роль, что и “столбец” или “поле записи”, не считая того, что:

  • поля могут представлять собой композитные структуры, такие как таблицы типа массива или ассоциативного массива,
  • полям не нужны имена.

В любом кортеже может быть любое количество полей, и это могут быть поля разных типов. Идентификатором поля является его номер, начиная с 1 (в Lua и других языках с индексацией с 1) или с 0 (в PHP или C/C++). Например, 1 или 0 могут использоваться в некоторых контекстах для обозначения первого поля кортежа.

Количество кортежей в спейсе не ограничено.

Кортежи в Tarantool’е хранятся в виде массивов MsgPack.

Когда Tarantool выводит значение в кортеже в консоль, используется формат YAML, например: [3, 'Ace of  Base', 1993].

Индекс — это совокупность значений ключей и указателей.

Как и для спейсов, индексам следует указать имена, а Tarantool определит уникальный числовой идентификатор («ID индекса»).

У индекса всегда есть определенный тип. Тип индекса по умолчанию – „TREE“. Все движки Tarantool’а предоставляют TREE-индексы, которые могут индексировать уникальные и неуникальные значения, поддерживают поиск по компонентам ключа, сравнение ключей и упорядоченные результаты. Кроме того, движок memtx поддерживает следующие индексы: HASH, RTREE и BITSET.

Индекс может быть многокомпонентным, то есть можно объявить, что ключ индекса состоит из двух или более полей в кортеже в любом порядке. Например, для обычного TREE-индекса максимальное количество частей равно 255.

Индекс может быть уникальным, то есть можно объявить, что недопустимо дважды задавать одно значение ключа.

Первый индекс, определенный для спейса, называется первичный индекс. Он должен быть уникальным. Все остальные индексы называются вторичными индексами, они могут строиться по неуникальным значениям.

Индекс может содержать идентификаторы полей кортежа и их предполагаемые типы (см. допустимые типы индексированных полей).

Примечание

Рекомендуется проектировать модель данных так, чтобы первичные ключи были первыми полями в котреже, чтобы их было быстрее сравнивать.

В нашем примере для начала определяем первичный индекс (под названием „primary“) по полю №1 каждого кортежа:

tarantool> i = s:create_index('primary', {type = 'hash', parts = {{field = 1, type = 'unsigned'}}}

Смысл в том, что поле №1 должно существовать и содержать целое число без знака для всех кортежей в спейсе „tester“. Тип индекса – „hash“, поэтому значения в поле №1 должны быть уникальными, поскольку ключи в HASH-индексах уникальны.

После этого мы определим вторичный индекс (под названием „secondary“) по полю №2 каждого кортежа:

tarantool> i = s:create_index('secondary', {type = 'tree', parts = {2, 'string'}})

Смысл в том, что поле №2 должно существовать и содержать строку для всех кортежей в спейсе „tester“. Тип индекса – „tree“, поэтому значения в поле №2 не должны быть уникальными, поскольку ключи в TREE-индексах могут не быть уникальными.

Примечание

Определения спейса и определения индексов хранятся в системных спейсах Tarantool’а _space и _index соответственно (для получения подробной информации см. справочник по вложенному модулю box.space).

Можно добавлять, опускать или изменять определения во время исполнения кода с некоторыми ограничениями. Более подробно о синтаксисе см. в справочнике по модулю box.

Подробнее об операциях с индексом читайте здесь.

Tarantool представляет собой базу данных и сервер приложений одновременно. Следовательно, разработчик часто работает с двумя наборами типов: типы языка программирования (например, Lua) и типы формата хранилища Tarantool (MsgPack).

Скалярный / составной MsgPack-тип   Lua-тип Пример значения
скалярный nil «nil» msgpack.NULL
скалярный boolean «boolean» (логическое значение) true
скалярный string «string» „A B C“
скалярный integer «number» 12345
скалярный double (числа с двойной точностью) «number» 1,2345
составной map (ассоциативный массив) «table» (таблица со строковыми ключами) {„a“: 5, „b“: 6}
составной array (массив) «table» (таблица с целочисленными ключами) [1, 2, 3, 4, 5]
составной array (массив) tuple («cdata») (кортеж) [12345, „A B C“]

В языке Lua тип nil (нулевой) может иметь только одно значение, также называемое nil (отображаемое как null в командной строке Tarantool’а, поскольку значения выводятся в формате YAML). Нулевое значение можно сравнивать со значениями любых типов с помощью операторов == (равен) или ~= (не равен), но никакие другие операции для нулевых значений не доступны. Нулевые значения также нельзя использовать в Lua-таблицах; вместо нулевого значения в таком случае можно указать msgpack.NULL

Тип boolean (логический) может иметь только значения true или false.

Тип string (строка) представляет собой последовательность байтов переменной длины, обычно представленную буквенно-цифровые символы в одинарных кавычках. Как в Lua, так и в MsgPack строки рассматриваются как бинарные данные без попыток определить набор символов строки или выполнить преобразование строки – кроме случаев, когда есть опциональное сравнение символов. Таким образом, обычно сортировка и сравнение строк выполняются побайтово, не применяя дополнительных правил сравнения символов. (Пример: числа упорядочены по их положению на числовой прямой, поэтому 2345 больше, чем 500; а строки упорядочены по кодировке первого байта, затем кодировке второго байта и так далее, таким образом, „2345“ меньше, чем „500“.)

В языке Lua тип number (число) – это число с плавающей запятой двойной точности, но в Tarantool’е можно использовать как целые числа, так и числа с плавающей запятой. Tarantool по возможности сохраняет числа языка Lua в виде чисел с плавающей запятой, если числовое значение содержит десятичную запятую или если оно очень велико (более 100 триллионов = 1e14). В противном случае, Tarantool сохраняет такое значение в виде целого числа. Чтобы даже очень большие величины гарантированно обрабатывались как целые числа, используйте функцию tonumber64, либо приписывайте в конце суффикс LL (Long Long) или ULL (Unsigned Long Long). Вот примеры записи чисел в обычном представлении, экспоненциальном, с суффиксом ULL и с использованием функции tonumber64: -55, -2.7e+20, 100000000000000ULL, tonumber64('18446744073709551615').

В Lua tables (таблицы) со строковыми ключами хранятся как ассоциативные массивы в MsgPack; Lua-таблицы с целочисленными ключами, начиная с 1, хранятся как массивы в MsgPack. Нулевые значения нельзя использовать в Lua-таблицах; вместо нулевого значения в таком случае можно указать msgpack.NULL

Тип tuple (кортеж) представляет собой легкую ссылку на массив MsgPack, который хранится в базе данных. Это особый тип (cdata), чтобы избежать конвертации в Lua-таблицу при выборке данных. Некоторые функции могут возвращать таблицы с множеством кортежей. Примеры с кортежами см. в box.tuple.

Примечание

Tarantool использует формат MsgPack для хранения в базе данных переменной длины. Поэтому, например, для наименьшего числа требуется только один байт, но для наибольшего числа требуется девять байтов.

Примеры запроса вставки с разными типами данных:

tarantool> box.space.K:insert{1,nil,true,'A B C',12345,1.2345}
---
- [1, null, true, 'A B C', 12345, 1.2345]
...
tarantool> box.space.K:insert{2,{['a']=5,['b']=6}}
---
- [2, {'a': 5, 'b': 6}]
...
tarantool> box.space.K:insert{3,{1,2,3,4,5}}
---
- [3, [1, 2, 3, 4, 5]]
...

Индексы ограничивают значения, которые может содержать MsgPack в Tarantool’е. Вот почему, например, тип „unsigned“ (без знака) представляет собой отдельный тип индексированного поля в сравнении с типом данных ‘integer’ (целое число) в MsgPack: оба содержат значения с целыми числами, но индекс „unsigned“ содержит только неотрицательные целые числовые значения, а индекс ‘integer’ содержит все целые числовые значения.

Вот как типы индексированных полей в Tarantool’е соответствуют типам данных MsgPack.

Тип индексированного поля Тип данных MsgPack
(и возможные значения)
Тип индекса Примеры
unsigned (без знака – может также называться ‘uint’ или ‘num’, но ‘num’ объявлен устаревшим) integer (целое число в диапазоне от 0 до 18 446 744 073 709 551 615, т.е. около 18 квинтиллионов) TREE, BITSET или HASH 123456
integer (целое число – может также называться ‘int’) integer (целое число в диапазоне от -9 223 372 036 854 775 808 до 18 446 744 073 709 551 615) TREE или HASH -2^63
number

integer (целое число в диапазоне от -9 223 372 036 854 775 808 до 18 446 744 073 709 551 615)

double (число с плавающей запятой с одинарной точностью или с двойной точностью)

TREE или HASH

1,234

-44

1,447e+44

string (строка – может также называться ‘str’) string (строка – любая последовательность октетов до максимальной длины) TREE, BITSET или HASH

‘A B C’

‘65 66 67’

boolean bool (логический – true или false) TREE или HASH true
array array (массив – список чисел, который представляет собой точки в геометрической фигуре) RTREE

{10, 11}

{3, 5, 9, 10}

scalar

bool (логический – true или false)

integer (целое число в диапазоне от -9 223 372 036 854 775 808 до 18 446 744 073 709 551 615)

double (число с плавающей запятой с одинарной точностью или с двойной точностью)

string (строковое значение, т.е. любая последовательность октетов)

Примечание: в сочетании различных типов порядок будет следующим: логические значения, затем числовые, затем строковые.

TREE или HASH

true

-1

1,234

‘’

‘ру’

По умолчанию, когда Tarantool сравнивает строки, он использует то, что мы называем «бинарной» сортировкой. Единственный фактор, который учитывается, это числовое значение каждого байта в строке. Таким образом, если строка кодируется по ASCII или UTF-8, то 'A' < 'B' < 'a', поскольку в кодировке „A“ (что раньше называлось «значение ASCII») соответствует 65, „B“ – 66, а „a“ – 98. Бинарная сортировка подходит лучше всего для быстрого детерминированного простого обслуживания и поиска с помощью индексов Tarantool’а.

Однако если необходимо распределение, как в телефонных справочниках и словарях, то вам нужна опциональная сортировка Tarantool’а – unicode и unicode_ci – которые обеспечивают 'a' < 'A' < 'B' и 'a' = 'A' < 'B' соответственно.

Опциональная сортировка использует распределение в соответствии с Таблицей сортировки символов Юникода по умолчанию (DUCET) и правилами, указанными в Техническом стандарте Юникода №10 – Алгоритм сортировки по Юникоду (Unicode® Technical Standard #10 Unicode Collation Algorithm (UTS #10 UCA)). Единственное отличие между двумя сортировками – вес:

  • сортировка unicode принимает во внимание уровни веса L1, L2 и L3 (уровень = „tertiary“, третичный),
  • сортировка unicode_ci принимает во внимание только вес L1 (уровень = „primary“, первичный), поэтому, например, „a“ = „A“ = „á“ = „Á“.

Для примера возьмем некоторые русские слова:

'ЕЛЕ'
'елейный'
'ёлка'
'еловый'
'елозить'
'Ёлочка'
'ёлочный'
'ЕЛь'
'ель'

…и покажем разницу в упорядочении и выборке по индексу:

  • с сортировкой по unicode:

    tarantool> box.space.T:create_index('I', {parts = {{1,'str', collation='unicode'}}})
    ...
    tarantool> box.space.T.index.I:select()
    ---
    - - ['ЕЛЕ']
      - ['елейный']
      - ['ёлка']
      - ['еловый']
      - ['елозить']
      - ['Ёлочка']
      - ['ёлочный']
      - ['ель']
      - ['ЕЛь']
    ...
    tarantool> box.space.T.index.I:select{'ЁлКа'}
    ---
    - []
    ...
    
  • с сортировкой по unicode_ci:

    tarantool> box.space.T:create_index('I', {parts = {{1,'str', collation='unicode_ci'}}})
    ...
    tarantool> box.space.S.index.I:select()
    ---
    - - ['ЕЛЕ']
      - ['елейный']
      - ['ёлка']
      - ['еловый']
      - ['елозить']
      - ['Ёлочка']
      - ['ёлочный']
      - ['ЕЛь']
    ...
    tarantool> box.space.S.index.I:select{'ЁлКа'}
    ---
    - - ['ёлка']
    ...
    

Фактически хорошая сортировка включает в себя гораздо больше, чем простые примеры эквивалентности заглавных и строчных букв, а также наличие или отсутствие диакритических знаков в алфавитах. Учитываются также варианты написания одного и того же символа, системы письменности без алфавита и специальные правила, которые применяются в отношении сочетания символов.

Последовательность – это генератор упорядоченных значений целых чисел.

Как и для спейсов и индексов, для последовательностей следует указать имена, а Tarantool определит уникальный числовой идентификатор («ID последовательности»).

Кроме того, можно указать несколько параметров при создании новой последовательности. Параметры определяют, какое значение будет генерироваться при использовании последовательности.

Параметры для box.schema.sequence.create()

Имя параметра Тип и значение Значение по умолчанию Примеры
start Integer. Значение генерируется, когда последовательность используется впервые 1 start=0
min Integer. Значения, ниже указанного, генерироваться не могут 1 min=-1000
max Integer. Значения, выше указанного, генерироваться не могут 9223372036854775807 max=0
cycle Логическое значение. Если значения не могут быть сгенерированы, начинать ли заново false cycle=true
cache Integer. Количество значений, которые будут храниться в кэше 0 cache=0
step Integer. Что добавить к предыдущему сгенерированному значению, когда генерируется новое значение 1 step=-1
if_not_exists (если отсутствует) Логическое значение. Если выставлено в true (истина) и существует последовательность с таким именем, то игнорировать другие опции и использовать текущие значения false if_not_exists=true

Существующую последовательность можно изменять, удалять, сбрасывать, заставить сгенерировать новое значение или ассоциировать с индексом.

Для первоначального примера сгенерируем последовательность под названием „S“.

tarantool> box.schema.sequence.create('S',{min=5, start=5})
---
- step: 1
  id: 5
  min: 5
  cache: 0
  uid: 1
  max: 9223372036854775807
  cycle: false
  name: S
  start: 5
...

В результате видим, что в новой последовательность есть все значения по умолчанию, за исключением указанных min и start.

Затем получаем следующее значение с помощью функции next().

tarantool> box.sequence.S:next()
---
- 5
...

Результат точно такой же, как и начальное значение. Если мы снова вызовем next(), то получим 6 (потому что предыдущее значение плюс значение шага составит 6) и так далее.

Затем создадим новую таблицу и скажем, что ее первичный ключ можно получить из последовательности.

tarantool> s=box.schema.space.create('T');s:create_index('I',{sequence='S'})
---
...

Затем вставим кортеж, не указывая значение первичного ключа.

tarantool> box.space.T:insert{nil,'other stuff'}
---
- [6, 'other stuff']
...

В результате имеем новый кортеж со значением 6 в первом поле. Такой способ организации данных, когда система автоматически генерирует значения для первичного ключа, иногда называется «автоинкрементным» (т.е. с автоматическим увеличением) или «по идентификатору».

Для получения подробной информации о синтаксисе и методах реализации см. справочник по box.schema.sequence.

В Tarantool’е обновления базы данных записываются в так называемые файлы журнала упреждающей записи (WAL-файлы). Это обеспечивает персистентность данных. При отключении электроэнергии или случайном завершении работы экземпляра Tarantool’а данные в оперативной памяти теряются. В такой ситуации WAL-файлы используются для восстановления данных так: Tarantool прочитывает WAL-файлы и повторно выполняет запросы (это называется «процессом восстановления»). Можно изменить временные настройки метода записи WAL-файлов или отключить его с помощью wal_mode.

Tarantool также сохраняет ряд файлов со статическими снимками данных (snapshots). Файл со снимком – это дисковая копия всех данных в базе на какой-то момент. Вместо того, чтобы зачитывать все WAL-файлы, появившиеся с момента создания базы, Tarantool в процессе восстановления может загрузить самый свежий снимок и затем зачитать только те WAL-файлы, которые были сделаны с момента сохранения снимка. После создания новых файлов, старые WAL-файлы могут быть удалены в целях экономии места на диске.

Чтобы принудительно создать файл со снимком, можно использовать запрос box.snapshot() в Tarantool’е. Чтобы включить автоматическое создание файлов со снимком, можно использовать демон создания контрольных точек Tarantool’а. Демон создания контрольных точек определяет интервалы для принудительного создания контрольных точек. Он обеспечивает синхронизацию и сохранение на диск образов движков базы данных (как memtx, так и vinyl), а также автоматически удаляет старые WAL-файлы.

Файлы со снимками можно создавать, даже если WAL-файлы отсутствуют.

Примечание

Движок memtx регулярно создает контрольные точки с интервалом, указанным в настройках демона создания контрольных точек.

Движок vinyl постоянно сохраняет состояние в контрольной точке в фоновом режиме.

Для получения более подробной информации о методе записи WAL-файлов и процессе восстановления см. раздел Внутренняя реализация.

Tarantool поддерживает следующие основные операции с данными:

  • пять операций по изменению данных (INSERT, UPDATE, UPSERT, DELETE, REPLACE) и
  • одну операцию по выборке данных (SELECT).

Все они реализованы в виде функций во вложенном модуле box.space.

Примеры:

  • INSERT: добавить новый кортеж к спейсу „tester“.

    Первое поле, field[1], будет 999 (тип MsgPack – integer, целое число).

    Второе поле, field[2], будет „Taranto“ (тип MsgPack – string, строка).

    tarantool> box.space.tester:insert{999, 'Taranto'}
    
  • UPDATE: обновить кортеж, изменяя поле field[2].

    Оператор «{999}» со значением, которое используется для поиска поля, соответствующего ключу в первичном индексе, является обязательным, поскольку в запросе update() должен быть оператор, который указывает уникальный ключ, в данном случае – field[1].

    Оператор «{{„=“, 2, „Tarantino“}}» указывает, что назначение нового значения относится к field[2].

    tarantool> box.space.tester:update({999}, {{'=', 2, 'Tarantino'}})
    
  • UPSERT: обновить или вставить кортеж, снова изменяя поле field[2].

    Синтаксис upsert() похож на синтаксис update(). Однако логика выполнения двух запросов отличается. UPSERT означает UPDATE или INSERT, в зависимости от состояния базы данных. Кроме того, выполнение UPSERT откладывается до коммита транзакции, поэтому в отличие от``update()``, upsert() не возвращает данные.

    tarantool> box.space.tester:upsert({999, 'Taranted'}, {{'=', 2, 'Tarantism'}})
    
  • REPLACE: заменить кортеж, добавляя новое поле.

    Это действие также можно выполнить с помощью запроса update(), но обычно запрос update() более сложен.

    tarantool> box.space.tester:replace{999, 'Tarantella', 'Tarantula'}
    
  • SELECT: провести выборку кортежа.

    Оператор «{999}» все еще обязателен, хотя в нем не должен упоминаться первичный ключ.

    tarantool> box.space.tester:select{999}
    
  • DELETE: удалить кортеж.

    В этом примере мы определяем поле, соответствующее ключу в первичном индексе.

    tarantool> box.space.tester:delete{999}
    

Подводя итоги по примерам:

  • Функции insert и replace принимают кортеж (где первичный ключ – это часть кортежа).
  • Функция upsert принимает кортеж (где первичный ключ – это часть кортежа), а также операции по обновлению.
  • Функция delete принимает полный ключ любого уникального индекса (первичный или вторичный).
  • Функция update принимает полный ключ любого уникального индекса (первичный или вторичный), а также операции к выполнению.
  • Функция select принимает любой ключ: первичный/вторичный, уникальный/неуникальный, полный/часть.

Для получения более подробной информации по использованию операций с данными см. справочник по box.space.

Примечание

Помимо Lua можно использовать коннекторы к Perl, PHP, Python или другому языку программирования. Клиент-серверный протокол открыт и задокументирован. См. БНФ с комментариями.

Операции с индексами производятся автоматически. Если запрос по манипулированию данными меняет данные в кортеже, то меняются и ключи в индексе для данного кортежа.

Простая операция по созданию индекса, которую мы рассматривали ранее, выглядит следующим образом:

box.space.space-name:create_index('index-name')

По умолчанию, при этом создается TREE-индекс по первому полю для всех кортежей (обычно его называют «Field#1»). Предполагается, что индексируемое поле является числовым.

Вот простой SELECT-запрос, который мы рассматривали ранее:

box.space.space-name:select(value)

Такой запрос ищет отдельный кортеж по первичному индексу. Поскольку первичный индекс всегда уникален, то данный запрос вернет не более одного кортежа. Можно также вызвать select() без аргументов, чтобы вернуть все кортежи.

Продолжим работу со спейсом „tester“, созданным в упражнениях из «Руководства для начинающих», но сначала его немного модифицируем:

tarantool> box.space.tester:format({
         > {name = 'id', type = 'unsigned'},
         > {name = 'band_name', type = 'string'},
         > {name = 'year', type = 'unsigned'},
         > {name = 'rate', type = 'unsigned', is_nullable=true}})
---
...

Добавим рейтинг „rate“ кортежам #1 и #2:

tarantool> box.space.tester:update(1, {{'=', 4, 5}})
---
- [1, 'Roxette', 1986, 5]
...
tarantool> box.space.tester:update(2, {{'=', 4, 4}})
---
- [2, 'Scorpions', 2015, 4]
...

И создадим еще один кортеж:

tarantool> box.space.tester:insert({4, 'Roxette', 2016, 3})
---
- [4, 'Roxette', 2016, 3]
...

Существующие вариации SELECT:

  1. Помимо условия равенства, при поиске могут использоваться и другие условия сравнения.
tarantool> box.space.tester:select(1, {iterator = 'GT'})
---
- - [2, 'Scorpions', 2015, 4]
  - [3, 'Ace of Base', 1993]
  - [4, 'Roxette', 2016, 3]
...

Можно использовать следующие операторы сравнения: LT (меньше), LE (меньше или равно), EQ (равно, результаты отсортированы в порядке возрастания по ключу), REQ (равно, результаты отсортированы в порядке убывания по ключу), GE (больше или равно), GT (больше). Сравнения имеют смысл только для индексов типа „TREE“.

Этот вариант поиска может вернуть более одного кортежа. В таком случае кортежи будут отсортированы в порядке убывания по ключу (если использовался оператор LT, LE или REQ), либо в порядке возрастания (во всех остальных случаях).

  1. Поиск может производиться по вторичному индексу.

При поиске по первичному индексу имя индекса можно не указывать. При поиске же по вторичному индексу имя индекса указывать необходимо.

tarantool> box.space.tester:create_index('secondary', {parts = {{field=3, type='unsigned'}}})
---
- unique: true
  parts:
  - type: unsigned
    is_nullable: false
    fieldno: 3
  id: 2
  space_id: 512
  type: TREE
  name: secondary
...
tarantool> box.space.tester.index.secondary:select({1993})
---
- - [3, 'Ace of Base', 1993]
...
  1. Поиск можно осуществить по некоторым частям ключа, используя его префикс. Обратите внимание, что частичный поиск по ключу доступен только в TREE индексах.
-- Создаем индекс, состоящий из трех частей
tarantool> box.space.tester:create_index('tertiary', {parts = {{field = 2, type = 'string'}, {field=3, type='unsigned'}, {field=4, type='unsigned'}}})
---
- unique: true
  parts:
  - type: string
    is_nullable: false
    fieldno: 2
  - type: unsigned
    is_nullable: false
    fieldno: 3
  - type: unsigned
    is_nullable: true
    fieldno: 4
  id: 6
  space_id: 513
  type: TREE
  name: tertiary
...
-- Выполняем частичный поиск
tarantool> box.space.tester.index.tertiary:select({'Scorpions', 2015})
---
- - [2, 'Scorpions', 2015, 4]
...
  1. Поиск может производиться по всем полям через запись в виде таблицы:
tarantool> box.space.tester.index.tertiary:select({'Roxette', 2016, 3})
---
- - [4, 'Roxette', 2016, 3]
...

либо же по одному полю (в этом случае используется таблица или скалярное значение):

tarantool> box.space.tester.index.tertiary:select({'Roxette'})
---
- - [1, 'Roxette', 1986, 5]
  - [4, 'Roxette', 2016, 3]
...

Примеры BITSET:

tarantool> box.schema.space.create('bitset_example')
tarantool> box.space.bitset_example:create_index('primary')
tarantool> box.space.bitset_example:create_index('bitset',{unique=false,type='BITSET', parts={2,'unsigned'}})
tarantool> box.space.bitset_example:insert{1,1}
tarantool> box.space.bitset_example:insert{2,4}
tarantool> box.space.bitset_example:insert{3,7}
tarantool> box.space.bitset_example:insert{4,3}
tarantool> box.space.bitset_example.index.bitset:select(2, {iterator='BITS_ANY_SET'})

Мы получим следующий результат:

---
- - [3, 7]
  - [4, 3]
...

поскольку (7 AND 2) не равно 0 и (3 AND 2) не равно 0.

Примеры RTREE:

tarantool> box.schema.space.create('rtree_example')
tarantool> box.space.rtree_example:create_index('primary')
tarantool> box.space.rtree_example:create_index('rtree',{unique=false,type='RTREE', parts={2,'ARRAY'}})
tarantool> box.space.rtree_example:insert{1, {3, 5, 9, 10}}
tarantool> box.space.rtree_example:insert{2, {10, 11}}
tarantool> box.space.rtree_example.index.rtree:select({4, 7, 5, 9}, {iterator = 'GT'})

Мы получим следующий результат:

---
- - [1, [3, 5, 9, 10]]
...

поскольку прямоугольник с углами в координатах 4,7,5,9 лежит целиком внутри прямоугольника с углами в координатах 3,5,9,10.

Кроме того, есть операции с итераторами с индексом. Их можно использовать только с кодом на языках Lua и C/C++. Итераторы с индексом предназначены для обхода индексов по одному ключу за раз, поскольку используют особенности каждого типа индекса, например оценка логических выражений при обходе BITSET-индексов или обход TREE-индексов в порядке по убыванию.

Полный список операций над индексами, таких как alter() (изменение индекса) и drop() (удаление индекса), приводится в справочнике для Вложенный модуль box.index.

Во вложенных модулях box.space и Вложенный модуль box.index содержится информация о том, как факторы сложности могут повлиять на использование каждой функции.

Фактор сложности Эффект
Размер индекса Количество ключей в индексе равно количеству кортежей в наборе данных. В случае с TREE-индексом: с ростом количества ключей увеличивается время поиска, хотя зависимость здесь, конечно же, не линейная. В случае с HASH-индексом: с ростом количества ключей увеличивается объем оперативной памяти, но количество низкоуровневых шагов остается примерно тем же.
Тип индекса Как правило, поиск по HASH-индексу работает быстрее, чем по TREE-индексу, если в спейсе более одного кортежа.
Количество обращений к индексам

Обычно для выборки значений одного кортежа используется только один индекс. Но при обновлении значений в кортеже требуется N обращений, если в спейсе N индексов.

Примечание по движку базы данных: Vinyl отклоняет такой доступ, если обновление не затрагивает поля вторичного индекса. Таким образом, этот фактор сложности влияет только на memtx, поскольку он всегда создает копию всего кортежа при каждом обновлении.

Количество обращений к кортежам Некоторые запросы, например SELECT, могут возвращать несколько кортежей. Как правило, это наименее важный фактор из всех.
Настройки WAL Важным параметром для записи в WAL является wal_mode. Если запись в WAL отключена или задана запись с задержкой, но этот фактор не так важен. Если же запись в WAL производится при каждом запросе на изменение данных, то при каждом таком запросе приходится ждать, пока отработает обращение к более медленному диску, и данный фактор становится важнее всех остальных.
Нашли ответ на свой вопрос?
Обратная связь