Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
MUMPS СУБД. Практика применения и опыт программирования.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
1.19. СТАНДАРТ И РАСШИРЕНИЯ 181
1. Замена ZALLOCATE / ZDEALLOCATE на различные формы ко­манды LOCK.
2. Замена $ZREFERENCE на $REFERENCE с предложением о воз­можности присваивания.
И, наконец, к важным особенностям стандарта на MUMPS можно отнести его абсолютную независимость от операционной системы, на которой выполняется MUMPS система, от типа многозадачности этой операционной системы, от процессорной архитектуры и очередности байт процессора, от числа бит и байт в одном символе и от типов и способов ввода - вывода.
При появлении и необходимости использовать новый тип ввода - вы­вода он добавляется в MUMPS систему наравне с имеющимися. Так, в частности, произошло в свое время с появлением сетевых протоколов на основе TCP/IP, ленточных накопителей, различного рода последова­тельных портов. При появлении новых операционных систем, как это произошло, например, с LINUX, MUMPS системы на них могут быть портированы зачастую в точности с тем же самым функционалом и непо­средственно сами программы, написанные на MUMPS, могут эт ого не заметить.
При появлении новых процессорных архитектур, как это произошло, например, с 64-битными процессорами, MUMPS программы точно так же этого могут не заметить, из-за того, что выполняются в стандарти­зированной среде выполнения.
Одним из важных отличий стандарта можно назвать его жесткую требовательность к тому, как и в каком порядке выполняются действия, но он совершенно никак не ограничивает собственно реализации по их внутреннему устройству, по форматам представления байткода или по характеру внутреннего хранения и представления данных. Это качество позволяет создавать, с одной стороны, прикладные программы, уверенно работающие на практически любой MUMPS системе, и сами реализа­ции систем, применяющие как новейшие процессоры, так и современные технологические и алгоритмические решения и типы ввода - вывода.
Известны даже реализации, исполнявшие MUMPS программы на компьютерах на процессоре Z80, работающие в DOS на 486-х процес­сорах и обслуживающие параллельно десятки клиентских подключений, работающие на редких экзотических RISC процессорах, разработанные только для определенной операционной системы или для самых разных.
Стандарту на язык удалось сохранить баланс между независимостью от прикладных систем и набором высокоуровневых операций общего на-
182 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
значения достаточно небольшого количества. Действительно, все клю­чевые операции языка по сути описываются примерно тремя десятками элементов, и на нем можно строить как полноценные СУБД, так и серве­ра приложений, при этом гибко реализуя необходимые методы работы с данными, не дожидаясь пока они будут поддерживаться в самой СУБД.
Глава 2

Глобалы

2.1 B-дерево

MUMPS системы хранят данные в так называемых глобалах. Этот тер­мин может звучать непривычно для современного разработчика, но имен­но в таком виде он устоялся и используется в технической документа­ции. В качестве синонимов глобалов используются термины глобальная переменная или глобальный массив.
Глобалы являются переменными среды исполнения, и доступны про­цессам по имени перед которым синтаксически ставится символ циркум­флекс, например
^Glo ^DATA(123)
Глобалы отличаются от других переменных тем, что собственно они и представляют саму базу данных в MUMPS. Данные глобалов хранятся в виде файлов на диске. MUMPS системы традиционно поддерживают от одной до нескольких баз данных, в каждой из готорых находится и хранится собственный набор глобалов. Разные базы данных могут иметь совпадающие имена глобалов, но это различные глобалы.
Хранение базы данных в файле - это обычная возможность использо­вать операционные системы, поддерживающие файловые системы. При этом необходимо сделать отступление для полноты описания. Формаль­но, использование именно файлов для СУБД не является необходимо­стью, и некоторые MUMPS системы, как и СУБД других классов, мо­гут использовать сырые неразмеченные разделы дисков для хранения баз данных. В этом случае СУБД самостоятельно управляет таким раз­делом. По сути, СУБД в любом случае содержит полный функционал
183
184 ГЛАВА 2. ГЛОБАЛЫ
кеширования блоков и их размещения в доступном пространстве на дис­ке, и СУБД не использует и не полагается в явном виде на, например, средства кеширования операционной системы. Вполне достаточно опе­раций чтения и записи порции данных, причем СУБД это и так всегда делает строго определенными порциями, кратными блоку.
В отличие от простейших систем баз данных, ориентированных на применение Memory Mapped Files (файлов, отображаемых в память), полноценным СУБД для доступа к базам данных эта функция не требу­ется, поскольку СУБД самостоятельно поддерживают довольно сложные алгоритмы синхронизации доступа к блокам, упорядочивания их чтения и записи, не полагаясь на то, как это делает операционная система.
Вернемся к глобалам MUMPS. Если используется только имя глоба­ла, то это означает обращение к глобалу в текущей базе данных теку­щего процесса. Для обращения к глобалу в определенной базе данных необходимо указать имя базы данных между символом циркумфлекса и именем глобала:
^|dbname|DATA(132) ^|"USER"|DATA(123)
Само имя базы данных может быть указано как вычисляемое выра­жение, главное чтобы результат выражения соответствовал имени базы данных.
Различные MUMPS системы могут использовать различную систему именования баз данных, в зависимости от реализации М-системы это может быть логическое имя, путь к каталогу, сочетание логических имен, например:
^|"USER"|DATA(123) ^|"D:\DB\user"|DATA(123) ^|"MGR:XXX"|DATA(123)
Стандарт языка MUMPS не налагает ограничений или требований на способ хранения глобалов и метод кодирования данных. Каждый из производителей выбирает формат и способ кодирования самостоятельно. Но, традиционно, в силу определения операций на глобалах, производи­тели М-систем используют организацию данных для глобалов в виде B* дерева.
Физически дерево организуется в виде сочетания блоков ссылок и блоков данных. В базе данных предусматриваются, кроме того, блоки учета занятости, блоки каталога глобалов, блоки хранения данных пре­вышающих размер блока и образующих цепочки, и, при необходимости, другие блоки служебного назначения.
2.1. B-ДЕРЕВО 185
Блок данных представляет собой чередование ключей и данных для
этих ключей.
key1
data1
key2
data2
...
Блок ссылок представляет собой чередование ключей и ссылок на
дочерние блоки.
ref0
key1
ref1
key2
ref2
...
Ссылки в блоке ссылок организуются таким образом, что ссылаются на дочерние блоки (которые могут быть либо также блоками ссылок либо блоками данных) в сортировке ключей. В приведенном примере ключ key1 делит дерево глобала на две части так, что все ключи меньше чем key1 следует искать по ссылке ref0, а все ключи которые больше или равен key1 следует искать по ссылке ref1. Соответственно, ключ key2 делит множество ключей на две части, ref1 указывает на ключи меньше чем key2 и ref2 указывает на ключи больше или равный key2. И так далее для всех ключей блока.
И в блоке данных и в блоке ссылок ключи хранятся сортированно, и система управления глобалами может применять специальные алгорит­мы вставки, поиска, удаления и перезаписи данных по ключам.
В блоке ссылок само значение ссылки используется не для получения значения (это делается в блоке данных), а для разделения областей по­иска. Конечно, если ключ в блоке ссылок образовался путем разделения пополам блока данных, а затем этот ключ был удален, то удаляется он не из блока ссылок, а из блока данных. Поэтому в результате работы в базе данных могут образовываться в блоках ссылок такие ключи, кото­рые не соответствуют реально существующим данным, но соответствуют правилам деления блоков на области поиска.
В блоке данных может находиться не само значение данных, а ссылка на цепочку блоков для длинного значения, не помещающегося в пределы блока. В большинстве случаев М-системы оперируют достаточно неболь­шими по длине данными, но при необходимости могут использовать и данные, существенно превышающие размер блока.
186 ГЛАВА 2. ГЛОБАЛЫ
Одним из примеров таких цепочек является хранение данных до 32 килобайт в системах MiniM или Cach´e в базах с размером блока 2 или 8 килобайт, а также хранение байткода и рутин в системе MSM, где объем одного элемента может составлять сотни килобайт.
Структурно имя глобала указывается как необязательное имя базы данных, имя глобала и последовательность индексов. Полная совокуп­ность имени и индексов, фактически, представляет собой единый ключ для одного значения. И глобал физически реализует отображение ключа на значение по этому ключу.
Одна из необязательных но распространенных особенностей хране­ния глобалов в современных М системах состоит в том, что глобалы преимущественно хранятся в формате с компрессией ключей. Если есть два ключа, и у них начальная часть индексов на какую-то длину совпа­дает, то система стремится по возможности сохранить второй ключ не полностью, а указав какая часть ключа используется от предыдущего ключа и далее хранить несовпадающую часть.
Для хранения ключей различные М системы используют разные спо­собы кодирования и определение совпадающей части ключей может вы­полняться по-разному - или совпадение по целым значениям индексов или совпадение по бинарному представлению индексов. Во втором слу­чае совпадение может прийтись на часть индекса.
Положим, что в базе данных надо хранить такие ключи:
^Data(123,"Volgograd",789) ... ^Data(123,"Vologda",456) ...
Вариант разбиения ключей для первого случая:
^Data(123,"Volgograd",789) ...
"Vologda",456) ...
Вариант разбиения ключей для второго случая:
^Data(123,"Volgograd",789) ...
"ogda",456) ...
Применение компрессии ключей традиционно приводит к уменьше­нию занимаемого глобалом места на диске без потерь данных и обычно без потерь скорости сравнения ключей. В некоторых случаях при пе­реносе данных из табличных источников в глобалы М систем может наблюдаться заметное уменьшение занимаемого данными места, если специфика хранения данных позволяет системе использовать компрес­сию ключей.
2.2. КОДИРОВАНИЕ ИНДЕКСОВ 187
Применяемые в М системах деревья традиционно управляются систе­мами хранения так, чтобы быть более балансированными. Абсолютная балансировка хранимого дерева не выполняется, поскольку могут суще­ствовать операции, при которых для сохранения полной балансировки может понадобиться переписать блоки ссылок и данных на много мега­байт. Степень сбалансированности деревьев у современных реализаций достаточно высокая и разработчики систем выбирают компромисс между сбалансированностью дерева и временем на его балансировку.
Нужно отметить, что хотя ключи в пределах одного блока следуют в определенном сортировкой ключей порядке, сами блоки дерева уже необязательно следуют друг за другом на диске в том же самом по­рядке. Сортированное хранение данных относится только к хранению в пределах каждого из блоков.
Размер одного блока ограничен, каким бы он ни был. Поэтому, ра­но или поздно, при вставке ключа в блок системе необходимо принять решение как вставить данные. В этом случае применяется расщепле­ние блока на две части. Примерно в середине блока выбирается ключ и выносится на более верхний блок в иерархии связей, начальная часть блока сохраняется (до ключа расщепления) а вторая часть (после ключа расщепления) записывается в новый блок. Номер нового блока запоми­нается с ключом расщепления в блоке более верхней иерархии. Если вставка ключа расщепления в более верхний блок также требует его расщепления, то операция повторяется уже с тем блоком.
После расщепления блока часть блока остается незанятой данными. Различного рода методы перелива данных, описанные в специализиро­ванной литературе по блансировке B* деревьев, обычно, не дают полного заполнения блока в любом произвольном случае. Поэтому практически все блоки М системы используются не полностью и существует некото­рое количество неиспользованных байт. Можно отметить, что среднеста­тистически при хранении данных B дерева в блоках степень занятости блоков составляет больше половины общего файлового пространства.

2.2 Кодирование индексов

При хранении глобалов разработчикам М систем необходимо обеспечить одновременное выполнение следующих условий:
1. Наименьшее время сравнения ключей
2. Сортировку строк согласно национальным алфавитам
188 ГЛАВА 2. ГЛОБАЛЫ
3. Сортировку чисел и строк согласно стандарту языка MUMPS
Задача уменьшения времени сравнения ключей обычно сводится к такому кодированию индексов, чтобы функция сравнения выполнялась наименьшее время. При выполнении операций с базами данных наиболее целесообразно применить специальное кодирование значений индексов в форму, наиболее удобную для сравнения. Само кодирование выполняется один раз, а сравнение много раз, поэтому достигается общий компромисс по общей производительности.
К наиболее удобной форме сравнения ключей относится простое срав­нение последовательности байт (в языке C это соответствует функции memcmp). В зависимости от реализации операция сравнения может быть ориентирована как на функцию memcmp для сравнения двух последо­вательностей байт на указанную длину, так и на функцию strcmp, ори­ентированную на сравнение последовательностей байт завершающихся нулевым байтом.
В любом случае, для кодирования индексов разработчики М систем стремятся выбрать такой способ, чтобы функция сравнения кодирован­ных ключей не требовала разбирать внутренности самого ключа в каком­либо структурировании и была максимально простой.
Проблема сортировки национальных алфавитов выражается в том, что есть алфавиты в которых кодирование символов соответствует их следованию в алфавите и есть алфавиты, в которых не соответствуют. В частности, в русском языке кодирование букв "Ё" и "Е" таково, что код буквы "Ё" меньше, чем код буквы "Е" и при обычной сортировке последовательностей байт слова с буквой "Ё" сортируются не по алфвиту.
Для решения проблемы сортировки национальных алфавитов в СУБД принято давать определение набора символов (charset) для строковых значений. В определении символов дается определение, как поднимать и опускать регистр символов при необходимости сравнения нечувстви­тельно к регистру и в каком порядке необходимо сортировать символы.
На примере проблемы буквы "Ё" опишем одно из возможных реше­ний. Кодирование букв "ДЕЁЖЗ" в кодировке Windows-1251 определено так:
Буква Код Д 196 Е 197 Ё 168 Ж 198 З 199
2.2. КОДИРОВАНИЕ ИНДЕКСОВ 189
Мы можем дать таблицу перекодирования символов так, чтобы ис­ходным байтам ставились в соответствие другие байты, обеспечивающие корректное следование в лексикографическом порядке, например:
Буква Код Результат Д 196 195 Е 197 196 Ё 168 197 Ж 198 198 З 199 199
Здесь для символов "ЖЗ" оставлены коды, буква "Ё" получила новый код, а буквы "ДЕ" получили смещение кодов.
В действительности, конечно, используется несколько иное значение кодов, поскольку с буквой "ё" надо поступить таким же образом и сдви­нуть коды также всех больших букв.
Таблица кодирования составлена так, чтобы перекодировать байты для следования в нужном порядке, и по самой задаче перекодирования для такой таблицы всегда существует обратная ей.
По прямой таблице СУБД перекодирует значения индексов для хра­нения и последующего сравнения, а обратную таблицу использует для получения действительного значения строки, какое было записано в стандартной входной кодировке символов. Например, если входная стро­ка была в кодировании Windows-1251, то и выходная будет также в ко­дировании Windows-1251, но храниться будет в кодированном представ­лении.
В принципе, для СУБД не имеет значения, в каких кодировках прихо­дят данные, главное чтобы было определено, как строки следует переко­дировать для сравнения. М системы могут оперировать национальными символами в произвольной кодировке и даже в зависимости от кодиро­вания принятого на используемой операционной системе. Обычно СУБД предоставляют способ дать определение символов для произвольного ко­дирования или самостоятельно поддерживают большой набор встроен­ных кодировок или таблиц перекодирования.
Третья проблема кодирования значений индексов состоит в том, что стандартом языка MUMPS определен порядок сравнения чисел и строк в качестве значений индексов. Несмотря на то, что в языке отсутствует декларация типа, существует вполне однозначное определение что яв­ляется числовым индексом а что строковым. В случае если М система обнаруживает что значение индекса подходит под определение канони­ческого числа, то система использует это значение как число. Общие правила сравнения значений индексов:
190 ГЛАВА 2. ГЛОБАЛЫ
1. Пустая строка меньше всех
2. Числа сортируются в алгебраическом порядке как числа
3. Любые числа меньше любых непустых строк
4. Строки сортируются в алфавитном порядке
Нужно отметить, что некоторые системы поддерживают возможность указать кроме стандартной сортировки также строго лексикографиче­скую, где числа сортируются как строки. Различие способов можно уви­деть на примере:
Значения Сортировка MUMPS Лексикографическая
"0" "-20" "-1" "-1" "-1" "-20" "12" "0" "0" "20" "12" "100" "-20" "20" "12" "100" "100" "20"
Возможность использовать для глобала строго лексикографическую сортировку может быть использовано в задачах, где разработчики само­стоятельно применяют кодирование, необходимое для решение задачи.
Вообще говоря, проблема усложняется еще и тем, что М система должна обеспечить сортировку и дробных чисел. Поэтому, если для це­лых чисел можно просто запомнить число в ключе, то для дробных это нельзя делать, поскольку дробные числа в общем случае нельзя сравни­вать во внутреннем представлении процессора.
Особенно сильно эта проблема проявляется в интерпретаторах, где дробные числа подвергаются арифметическим преобразованиям и пре­образованиям из строки и в строку. Например, простой тест показывает первые 5 найденные чисел, для которых после преобразования в строку и обратно совпадают строковые значения, но не совпадают внутренние бинарные:
#include <stdio.h> #include <stdlib.h>
#pragma argsused int main(int argc, char* argv[]) {
double d1; double d2;