Eloquera V

краткое описание / немного истории / установка / режимы работы базы: service, inmemory, desktop / восстановление базы
конфигурация / программная конфигурация / простейшие операции CRUD / insert / update / refreshMode / delete
построение запросов / joins / параметры / массивы / шаблонные контейнеры / order by / доступные функции / almos
хранимые процедуры
родные и динамические объекты / работа с массивами / контейнеры / фильтрация типов, свойств и полей / backup and restore / эволюция типов / fulltext search / индексация / под капотом

«Родные» и динамические объекты

Под родными объектами в данном случае подразумеваются любые типы принадлежащие CLR или созданные вами. Eloquera может на лету (в runtime) конвертировать динамические объекты в «родные» и обратно.

Внимание!

Для использования этого функционала должно быть открыто соединение к базе.

Основные методы для конвертации:

  • ToNative<ConcretType>()
  • FromNative(variable)

Пример для уже открытой базы по созданию динамического объекта:

При обновлении данных применяются следующие схемы работы:

  • Обновление через родной тип

0    Динамический тип переводим в «родной» тип

0    Изменяем «родной» тип

0    Обновляем (синхронизируем) динамический тип с помощью FromNative

  • Обновление через динамический тип

0    Существует переменная конкретного типа с данными динамического

0    Изменяем динамический тип

0    Обновляем (синхронизируем) «родной» тип с помощью ToNative<T>(variable)

Пример на первую схему:

Пример на вторую схему:

 

Работа с массивами

Работа с массивами является одной из фич базы Eloquera.

Основная рекомендация, которую вы можете принять за правило, звучит так: сохранять и получать объекты следует с использованием Dynamic , всю остальную работу делать с оригинальными типами. Другой хорошей рекомендацией является указание от разработчиков использовать именно массивы, а не List<>, Dictionary<,>  —  так как это всего лишь синтаксический сахар.

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

Создание массивов, никаких неожиданностей:

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

Как я уже упомянул, при работе с List<T> рекомендуется перевести его в массив перед сохранением.

В реальных приложениях опять же постоянно приходится добавлять новые элементы в массивы. Вот как это можно проделать с динамическими типами, обратите внимание, что конкретный тип при создании оборачивается в динамический:

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

Так как массивы суть ссылочные объекты и структура массива не изменилась, то можно просто сохранить измененный объект.  Eloquera корректно его опознает в своей структуре и обновит. Если одновременно с изменением были добавлены новые элементы, надо будет передать на сохранение весь массив.

Контейнеры

В базе данных есть поддержка полностью изолированных хранилищ для динамических объектов – контейнеры. Контейнеры позволяют хранить объекты по логическим группам, к примеру, «еда», «книги», «игры».  Еще раз сделаю акцент на том, что контейнеры изолированы, т.е. если один и тот же объект поместить в 2 контейнера, то изменение в объекте в первом контейнере не повлечет за собой изменения объекта во втором контейнере, он останется неизменным.

Сохранение вложенных объектов так же будет сделано по контейнерам и они будут независимыми.

Пример:

Естественно, что присутствует возможность получить все контейнеры, созданные в системе. Метод для получения этого списка соответствует принципу наименьшего удивления и носит имя ListContainers.

Extras

Движок Eloquera индексирует все поля динамических объектов, однако порой в объекте хранятся сырые данные представляющие собой картинки, зашифрованные данные, сериализованные данные. Эти объекты с вероятностью 99,9% никогда не будут участвовать в запросах. В таких случаях массивы могут быть объявлены как дополнения – они не будут индексированы для увеличения скорости обработки (сохранения) данных.

Для создания дополнения надо добавить знак решетки перед именем.

 

Дополнительные возможности

Фильтрация типов

Движок базы данных позволяет настраивать фильтры для добавления информации в базу при сохранении типов. Т.е. с помощью метода IgnoreType можно указать какие  типы игнорировать при сохранении комплексных типов.  Все поля, свойства или объекты, помеченные для игнорирования, не сохранятся в базе.  Игнорируемые поля и свойства будут восстановлены со значениями по умолчанию.

Пример использования:

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

Важно!

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

Фильтрация свойств и полей

Кроме того, что вы можете указать типы для игнорирования, существует возможность указать конкретные поля, которые не будут сохраняться в базу данных. Свойства указываются в виде лямбда-выражений вида ()=>myClassInstance.MyPropertyToBeIgnored, в качестве параметра для метода IgnoreProperty. После этого все проверки будут проводиться движком базы.

 

Backup and restore

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

Пример создания резервной копии:

И пример восстановления данных:

 

Регистрирование типов

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

 

Эволюция типов

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

В описанной ситуации на помощь могут прийти динамические объекты. Перевести «родные» объекты в динамические в промежуточной базе. Затем составить в новый тип и записать обратно. Модификация данных в одной и той же базе может быть слишком сложной и громоздкой.

Как пример обновления типов:

Full text search

Данная возможность может рассматриваться как немного магии над свойствами объекта.

Идея в том, что можно делать множество трансформаций в свойствах объекта и полученный результат использовать в запросе. Допустим, у нас есть куча товаров, которые описываются километрами текста. По всем товарам можно запустить полнотекстовый поиск следующим образом:

Запрос:

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

Еще пример на работу со свойствами:

Увеличение производительности

Индексация

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

Для того чтобы свойство или поле стало индексируемым необходимо применить к нему атрибут Index.

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

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

Индексация будет применяться только к вновь сохраненным объектам.

Для динамических объектов индексы создаются всегда для всех полей, кроме тех, которые помечены как «дополнения» (начинаются с решетки).

 

Настройки в конфигурации

Перед работой базы, исходя из специфики проекта и железа, можно более тонко настроить производительность базы данных. Вот примеры использования и что надо сделать для ускорения работы с базой:

  • Множество строковых полей в объекте – рекомендуется увеличить в конфигурации параметр VarSectorSize
  • Множество индексируемых полей – увеличить значение поля IndexCacheSize, попробовать поиграть с настройками IndexNodeSize в сторону уменьшения значения.
  • Быстрый жесткий диск – попробуйте уменьшить MemoryFootPrint. Значение более 100 будет считаться за размер в KB, менее 100 будет считаться за проценты.
  • Множество запросов к непроиндексировнным данным – будет полезно увеличить ShallowReadAhead и уменьшить значение ShallowReadThreshold

 

Под капотом

На данный момент база данных Eloquera свободно распространяемый продукт с закрытым исходным кодом. Дизайн базы изначально проектировался для корпоративного (Enterprise) использования, т.е. для баз от 100ГБ и более. Это явно не для встроенного использования, что не отменяет локального использования конечно.

Внутреннее устройство, API, и прочие детали не раскрываются из-за коммерческой тайны, однако общее внутреннее устройство базы известно и показано ниже. Однако следует помнить о том, что это лишь отображение общей идеи, в то время как база данных очень сложный продукт и невозможно указать на диаграмме связи и значимые типы так, чтобы сохранить ясность и хоть сколько-нибудь свободного места на листе формата А3.

Тем не менее, вот как все выглядит внутри:

После примера на эволюцию данных у вас может сложиться впечатление, что внутренне представление всех типов будет  Dynamic с какой-то более строгой проверкой типов, однако это не так. Для хранения «родных» объектов используется специальная мета-таблица для работы с данными.

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

Мета также используется для сборки и разборки объектов (сборка и разборка написана на MSIL, стандартная сериализация не используется по причине крайней медленности).

Когда новый тип сохраняется, клиент генерирует MSIL код на лету, компилирует его и использует откомпилированный код для сборки и разборки объектов. Получается в сотни раз быстрее, чем стандартная сериализация в .NET. Вот что фактически происходит внутри.

То есть, клиент сам себя наращивает кодом для работы с данным типом.

Оставить комментарий