БД. Справочники. Примеры на MUMPS (Cache Object Script)

На хабре часто можно встретить различные статьи о том как сделано то или то, с непосредственной реализацией, кодом, примерами, обоснованиями (пусть даже спорными). Кто-то выкладывает пример контролла, кто-то даёт практические советы по яваскрипту. Однако я не видел, чтобы кто-нибудь, рассказывал об организации структуры БД. Дальше каких-то школьных примеров это не заходит (если ошибаюсь поправьте и дайте ссылки). Нет, холивары SQL vs NoSQL меня не интересуют. По моему скромному убеждению — СУБД вторична в вопросах организации БД. Вопросы производительности конкретных СУБД становятся актуальными далеко не сразу. Какая бы ни была выбрана СУБД, под определённую задачу, к производительности предъявляется всего одно требование — производительность должна быть достаточной. А вот пути достижения этой самой достаточности, способы удобно и красиво разместить данные — чтобы быстро и легко их извлекать, организация справочников и индексов, ввода и вывода, способы масштабирования и/или изменения структуры БД в течении жизни, используемые методики, решённые и нерешённые проблемы, полезные рецепты и советы — это всё то, о чём я хочу поговорить.

Разработка структур БД очень интересный и нетривиальный процесс. В этой обширной области встречается мало живых примеров, которые можно посмотреть, обсудить, спросить, узнать. Неужели вам, разработчики БД, всегда всё ясно что и как делать? Давайте делиться знаниями, давайте спрашивать, рассказывать, обсуждать. Какая разница таблица или объект или глобал — важно какой смысл вкладывается, какие связи выстраиваются, какими средствами эти связи реализовываются.

Я не работаю в интерсистемс, это указано в моём профайле только чтобы иметь возможность размещать статьи в их блог (отдельного хаба для MUMS или COS на хабре нет). Так что описанные мной методы могут не совпадать с «заводскими» рекомендациями использования СУБД Cache и языка Cache Object Script.

Пару дней назад был опубликован перевод, в котором мой подход, к программированию БД, называли экстремальным — я с этим не совсем согласен. В комментариях, было как минимум три человека (Ogoun uaoleg 4dmonster), которые сказали, что им было бы интересно посмотреть на живое использование MUMPS и узнать почему не надо бояться глобалов. Для этих людей и всех тех, кому интересно обсудить затронутые мной темы, я и пишу данную статью.

Определение:

Справочник это медленно меняющийся перечень уникальных позиций, содержащий краткие и точные сведения научного, производственного или прикладного характера, объединенных единой тематикой. Например адресные справочники (страны, города, улицы …) В определение википедии я не случайно добавил «медленно меняющийся».

Требования:

Основные требования предоставляемые к справочнику:

  • Операция получения названия элемента справочника (retrieve) должна выполнятся быстро.
  • Название любого элемента справочника можно изменить в одном месте, и это изменение применится во всей системе.

Рассмотрим более подробно:

Быстро получить название элемента справочника — означает не искать. То есть просто прочитать в известном месте и выдать. Это говорит о том, что, к медленно меняющейся информации обращаются часто. Ответ надо выдавать быстро. Как это делается в Cache я покажу далее. Если какой-то там специализированный поиск (найти все города на букву А удалённые от города N не более чем на x км) — ещё может себе позволить кушать процессорное время — то выдача названия элемента справочника — нет.

Изменение названия элемента справочника в одном месте означает что операция updateName по сложности и времени выполнения, аналогична операции retrieve, за исключением случаев, когда требуется проверка на допустимость нового имени. Но даже в этом случае никакая перестройка и переиндексация больших наборов данных, в которых используется данный элемент справочника, не требуется. Это логично вытекает из одной простой особенности любых справочников и вообще данных — в названиях могут быть ошибки. То есть вы можете спроектировать разработать и запустить систему, любой степени сложности и нужности, а через какое-то время, окажется, что допущена ошибка в названии. Вам надо эту ошибку исправить. Вы не хотите проверять и долго переиндексировать всю, или большую часть, вашей системы для исправления этой ошибки. Вы не хотите чтобы старые/новые аналитические/оперативные отчёты или статистика — перестали согласовываться друг с другом из-за изменения одного названия. Вы не хотите заново генерировать seo и прочие шаблоны страниц вашего сайта. Вы хотите изменить одно название в одном месте и забыть об этом. Конечно, большинству разработчиков БД, наверное, это моё требование, покажется очевидным, и не заслуживающим такого большого количества букв. Но оказалось, на практике, оно выполняется значительно реже, чем можно себе представить.

Тест

Давайте проведём простой тест. Те из вас, у кого есть свой сайт (не обязательно чтобы он принадлежал вам, это может быть просто сайт вашей компании, или вашего клиента, к которому вы имеете доступ и можете вносить на нём изменения) попробуйте сейчас, в одном месте, изменить название любого элемента справочника (например города). К примеру Санкт-Петербург — переименуйте в Питер, или Киев — в Мать городов русских или ещё что-нибудь во что-нибудь. Можете ли вы сделать это в одном месте? Изменилось значение тега на вашем сайте? Увидели ли вы это изменение на странице расширенного поиска (если она у вас есть)? Не изменились ли после этого адреса некоторых ваших страниц на сайте? Автоматически ли изменились заголовки тайтлы и дескрипшены связанных страниц? Нет, я не рассматриваю здесь сложные системы синтаксического анализатора, замены окончаний слов и прочего — я просто спрашиваю у вас честный ответ — вы можете изменить название одного элемента в одном месте так — чтобы везде (кроме неструктурированных текстов) это изменение применилось? Кеширование здесь, для простоты, не рассматриваем. (Опрос внизу).

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

  • Необходимо иметь возможность хранить названия элементов справочника на различных языках соблюдая при этом предыдущие требования. Операция retrieve для любого нового языка должна выполнятся также быстро.
  • Необходимо хранить историю изменения элементов справочника (названий, структурных позиций, и прочих характеристик) с возможностью проследить и выдавать информацию зависимую от времени t (как этот город назывался вчера, или t лет назад).

Эти требования названы дополнительными, потому что не для всех БД они важны и нужны, попросту говоря — не всегда они являются требованиями. К примеру возможность хранить названия элементов на различных языках — надо наверное не всем, однако, даже если, ваш сайт, заточен под один конкретный язык или регион — не спешите вычеркивать эту функциональность из списка требований — возможно она пригодится и вам. К примеру, некоторые урлы страниц — содержат в себе латинское название тех или иных элементов справочника, и если это название, каждый раз будет генерится на основании справочного названия — то при updateName — вы можете получить новый урл для старой страницы, только из-за исправления ошибки в названии.

Пример

В справочнике сайта example.com находится элемент c названим Киев. Все примеры относящиеся к этому городу и сайту находятся на странице example.com/kiev значение kiev — было получено простым транслитом слова Киев + перевод в нижний регистр. Теперь, предположим, вы меняете название элемента справочника на Мать городов русских. Так как ваша страница привязана к транслиту названия элемента — и название изменилось, меняется и сам транслит, меняется и адрес страницы example.com/mat_gorodov_russkih
Этих проблем можно избежать задавая название элемента справочника на нескольких языках. Пусть первый будет ru а второй partUri. Тогда при изменении названия на одном языке, оно автоматически не изменится на другом (как минимум этим можно управлять). И адрес страницы останется прежним.

Хранение истории изменений элементов справочника — функциональность, которая требуется далеко не всегда, реализовывается она чуть сложнее, чем многоязычность или изменение имени, и главное — влечёт за собой увеличение времени, требуемого на изменение элемента справочника. Однако, при грамотной реализации, это время увеличивается незначительно, а главное, исходя из того, что справочник, это медленно меняющаяся информация, ничего страшного в длительном изменении элемента нет.

Реализация

Пусть все элементы справочника хранятся в глобале ^Dictionary

Глобал — это глобальная переменная, изменения в которой сохраняются на диске. Индексы переменной идут в скобках после имени переменной через запятую. Например:
^ГлобальнаяПеременная(«индекс1»,«индекс2»,…,«индексN»)=«значение»
Индексы и значения берутся в кавычки — только если это не числа. Индексом может быть также другая переменная (подробнее об этом позже).

Примем что:

  1. -й индекс глобала ^Dictionary — будет означать онтологию (грубые классификации справочников) — наша онтология Vehicle (транспортные средства)
  2. -й индекс — будет непосредственно названием справочника — TransmissionType (тип трансмиссии)
  3. -й индекс — будет идентификатором элемента справочника (причём все идентификаторы уникальны, даже в пределах различных справочников и онтологий)
  4. -й индекс — номер версии элемента (0-текущая актуальная версия, остальные — история)
  5. -й индекс — это название свойства элемента

Имя глобала и смысл, вкладываемый в каждый индекс — придуманы мною (разработчиком) — это ни в коем случае не правило, или обязательная языковая конструкция. Описание, этих самостоятельных правил, также имеется — однако я его приведу позже (возможно в следующих статьях). На данный момент мы просто посмотрим как может быть организован простейший одноуровневый справочник, безо всякой вложенности и прочего. Данные приводящиеся в примере взяты из реальной живой использующейся БД. Выведем информацию по нашему справочнику — выполним команду:

zw ^Dictionary(«Vehicle»,«TransmissionType»)

^Dictionary("Vehicle","TransmissionType",1,0,"UpdateTime")="62086,66625" ^Dictionary("Vehicle","TransmissionType",1,0,"uid")=888 ^Dictionary("Vehicle","TransmissionType",2,0,"UpdateTime")="62086,66625" ^Dictionary("Vehicle","TransmissionType",2,0,"uid")=888 

Комманда zw выводит значения переменной(глобальной или локальной) со всеми определёнными индексами.

Давайте внимательно посмотрим на то что мы вывели. Итак мы распечатали все элементы справочника TransmissionType онтологии Vehicle. Как видно в данном справочнике всего два элемента с идентификаторами 1 и 2. Также очевидно, раз 4й индекс — только 0 — то все элементы этого справочника актуальны, и после добавления ни разу не изменялись (истории нет). У каждого элемента справочника есть всего два свойства: UpdateTime (дата и время обновления в формате Cache) и uid (идентификатор пользователя сделавшего изменение). Ещё раз обратите внимание на практически полное отсутствие служебных слов и символов в команде и результате.

Вы можете изменить название любого элемента справочника в одном месте так — чтобы это изменение применилось во всей системе?

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

Никто ещё не голосовал. Воздержавшихся нет.

ссылка на оригинал статьи http://habrahabr.ru/company/intersystems/blog/175773/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *