Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:MUMPS СУБД. Практика применения и опыт программирования.pdf
X
- •Предисловие
- •Введение
- •Среда исполнения
- •Команды
- •Команды присваивания
- •Условные команды
- •Команды передачи управления
- •Команды ввода-вывода
- •Служебные команды
- •Постусловия
- •Операторы
- •Переменные
- •Числа и строки
- •Функции
- •$DATA
- •$GET
- •$ORDER
- •$NEXT
- •$QUERY
- •$NAME
- •$QLENGTH
- •$QSUBSCRIPT
- •$ASCII
- •$CHAR
- •$EXTRACT
- •$PIECE
- •$LENGTH
- •$REVERSE
- •$FIND
- •$TRANSLATE
- •$JUSTIFY
- •$FNUMBER
- •$TEXT
- •$RANDOM
- •$VIEW
- •$SELECT
- •$STACK
- •Списковые функции
- •Битовые функции
- •Модули
- •Рутины
- •Передача параметров
- •Неопределенные значения
- •Шаблоны
- •Косвенность
- •Косвенность имени
- •Косвенность индексов
- •Косвенность метки
- •Косвенность аргумента
- •Косвенность шаблона
- •Интерпретатор
- •Голая ссылка
- •Очередность выполнения
- •Очередность вычисления выражений
- •Очередность вычисления имен
- •Стекование $test
- •Комментарий
- •Стандарт и расширения
- •Глобалы
- •B-дерево
- •Кодирование индексов
- •Размер блока
- •Кеширование блоков
- •Структуры
- •Индексация
- •Группировка
- •Каноничность индексов
- •Маппинг
- •Индексация данных
- •Общие принципы
- •Механизм поддержки индекса
- •Простой индекс
- •Составной индекс
- •Покрывающий индекс
- •Кластерный индекс
- •Хеш-индекс
- •Битмап индекс (bitmap)
- •Битслайс индекс (bitslice)
- •Нормирование значений
- •Выборки по индексу
- •Многоиндексная выборка (zig-zag)
- •Дифференциальное индексирование
- •Индексация длинных атрибутов
- •Межтабличный индекс
- •Индекс с условием на вставку
- •Индекс на вычисляемый атрибут
- •Индекс поиска по фрагменту
- •Индексация для шаблона (like)
- •Индексация уникального атрибута
- •Массовое перестроение индексов
- •Операции с древовидными индексами
- •Операции с битовыми индексами
- •Сортировка по индексу
- •Статистики и кардинальность
- •Конкурентный доступ
- •Параллельность выполнения
- •Блокировки
- •Функция $INCREMENT
- •Транзакции
- •Блокировки в транзакциях
- •Функция $BIT
- •Дедлоки
- •Обработка ошибок
- •Состояние ошибки
- •ZTRAP
- •GT.M
- •MiniM
- •ETRAP
- •Определение
- •$ETRAP
- •$ECODE
- •$ESTACK
- •Ошибки в обработчике ошибок
- •$STACK()
- •Трассировка
- •BREAK
- •MiniM Debugger
- •Serenji Debugger
- •Внешний мир
- •Общие принципы
- •Терминальный интерфейс
- •Сокеты
- •HTTP клиент
- •Вебсервер на MUMPS
- •WebLink
- •Проблемы HTTP
- •Поверх HTTP
- •Подключаемые DLL (SO)
- •Файлы
- •Внешние процессы
- •Порты
- •Практика применения
- •Терминальный режим
- •Редакторы рутин
- •Экспорт и импорт
- •Препроцессор
- •Формат $HOROLOG
- •Опции устройств
- •$X и $Y
- •Возврат результатов
- •Возврат по значению ($$)
- •Возврат по ссылке
- •Запись в предопределенную переменную
- •Возврат значений косвенно
- •Итеративный возврат
- •Потоковый возврат
- •%Z - рутины
- •Планирование файлов
- •Память и сборка мусора

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;
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
