Добавил:
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 - рутины
- •Планирование файлов
- •Память и сборка мусора

3.3. ПРОСТОЙ ИНДЕКС 231
системой) на запись как совокупность значений атрибутов, то простой
индекс отображает значение индексируемых атрибутов на идентификатор или набор идентификаторов записей.
Наличие такого быстрого отображения и реализует способ быстрого
поиска записи по значению атрибута. Положим, что в нашем случае
записи имеют структуру
^Data(id)=Figure~Color~Count
Тогда при наличии индекса по фигуре мы должны поддерживать актуальность дополнительной структуры данных
^Index(Figure,id)=""
Эта структура позволяет, задав значение фигуры, получить набор
идентификаторов записей, в которых встречается это значение фигуры.
В случае поддержки нескольких индексов, конечно, структура должна
быть усложнена:
^Index("Figure",Figure,id)=""
^Index("Color",Color,id)=""
^Index("Count",Count,id)=""
с целью повторного использования имени индексной глобали.
Можно также выбрать вариант хранить индексы по разным атрибутам в разных глобалях, но обычно придерживаются использования
одной. Это сокращает список используемых глобалов и упрощает сопровождение и модификацию программ.
Простой индекс используется как в задачах выборки данных по условию, так и определения существования записей с заданными значениями
атрибутов. Что используется при реализации ограничений различного
вида.
Небольшой пример реализации простых индексов:
ind01 ; простые индексы, автоматический идентификатор
q
CreateRecords()
k ^Index
k ^Data
n i,Figures,Colors,Counts,Figure,Color,Count,id
s Figures="квадрат~круг~отрезок~треугольник"
s Colors="красный~зелёный~синий~белый"
s Counts="2~5~12~8"
f i=1:1:12 d
. s Figure=$p(Figures,"~",$r(4)+1)

232 ГЛАВА 3. ИНДЕКСАЦИЯ ДАННЫХ
. s Color=$p(Colors,"~",$r(4)+1)
. s Count=$p(Counts,"~",$r(4)+1)
. s id=$$InsertRecord(Figure_"~"_Color_"~"_Count)
q
InsertRecord(RecordValues)
n id s id=$i(^Data)
l +^Data(id)
s ^Data(id)=RecordValues
d InsertIndexRecords(id,RecordValues)
l -^Data(id)
q id
DeleteRecord(id)
q:’$d(^Data(id))
l +^Data(id)
n RecordValues s RecordValues=$g(^Data(id))
d DeleteIndexRecords(id,RecordValues)
k ^Data(id)
l -^Data(id)
q
UpdateRecord(id,RecordValues)
q:’$d(^Data(id))
l +^Data(id)
n OldRecordValues s OldRecordValues=$g(^Data(id))
d DeleteIndexRecords(id,OldRecordValues)
s ^Data(id)=RecordValues
d InsertIndexRecords(id,RecordValues)
l -^Data(id)
q
DeleteIndex(IndexName)
k ^Index(IndexName)
q
InsertIndexRecords(id,RecordValues)
d InsertIndexRecord("Figure",id,$p((RecordValues),"~",1))
d InsertIndexRecord("Color",id,$p((RecordValues),"~",2))
d InsertIndexRecord("Count",id,$p((RecordValues),"~",3))
q
DeleteIndexRecords(id,RecordValues)
d DeleteIndexRecord("Figure",id,$p((RecordValues),"~",1))
d DeleteIndexRecord("Color",id,$p((RecordValues),"~",2))
d DeleteIndexRecord("Count",id,$p((RecordValues),"~",3))
q
InsertIndexRecord(IndexName,id,Value)
l +^Index(IndexName,Value,id)
s ^Index(IndexName,Value,id)=""
l -^Index(IndexName,Value,id)
q
DeleteIndexRecord(IndexName,id,Value)
l +^Index(IndexName,Value,id)
k ^Index(IndexName,Value,id)

3.4. СОСТАВНОЙ ИНДЕКС 233
l -^Index(IndexName,Value,id)
q
3.4 Составной индекс
Если простой индекс отображает значение одного атрибута на идентификатор или набор идентификаторов строк, то составной индекс отображает совокупность значений двух или более атрибутов на идентификатор
или набор идентификаторов строк.
Структурно индексные записи содержат значения не одного, а двух
или более атрибутов в определенном порядке. При этом значения атрибутов могут быть как указаны по отдельности в подъиндексах узлов,
так и может быть применена функция, получающая по двум или более
значениям одно значение, которое не можут быть получено при других
значениях атрибутов. Приведем простой пример с одним составным индексом по атрибутам Figure и Color. В первом случае, при раздельном
указании значений атрибутов в индексе:
^Index("FigureColor",Figure,Color,id)=""
Во втором случае при использовании, например, функции $listbuild:
^Index("FigureColor",$lb(Figure,Color),id)=""
Или при использовании одного значения в виде строки с разделителем:
^Index("FigureColor",Figure_"~"_Color,id)=""
Вопрос выбора функции получения составного значения по нескольким оставим программисту. Думаю, что это лучше решать в каждом
конкретном случае. В расчет следует принимать не только уникальность
её результата для значений аргументов, но и возможность использовать
индексную сортировку при выборке данных, а также время вычисления
индексирующего значения.
Составные индексы применяются в выборках данных, где задано условие на два атрибута одновременно. Фактически, имея составной индекс
по этим атрибутам, мы получаем максимальную скорость выборки.
Кроме указания идентификатора записи в подъиндексе узла индексной записи можно также применить хранение набора идентификаторов
в одном значении. Например:

234 ГЛАВА 3. ИНДЕКСАЦИЯ ДАННЫХ
^Index("FigureColor",Figure,Color)=idlist
Здесь idlist - список идентификаторов строк. Такая организация индекса позволяет организовать эффективное покрытие. Покрывающим индексом называется индекс, который может быть применен в другом типе
выборки. В случае составного индекса например это могут быть узлы
двух видов:
^Index("FigureColor",Figure)=FigureIdList
^Index("FigureColor",Figure,Color)=FigureColorIdList
Например, пусть есть записи
1 шарик красный 20
2 шарик зеленый 12
3 квадрат синий 5
Им будут соответствовать индексные записи:
^Index("FigureColor","шарик")=$lb(1,2)
^Index("FigureColor","шарик","красный")=$lb(1)
^Index("FigureColor","шарик","зеленый")=$lb(2)
^Index("FigureColor","квадрат")=$lb(3)
^Index("FigureColor","квадрат","синий")=$lb(3)
Второй вариант организации покрывающего индекса есть применение
операции не $o() для выборки данных, а операции $q(). При ее использовании в качестве покрывающего индекса может быть использована
начальная простая структура вида
^Index("FigureColor",Figure,Color,id)=""
В данном случае индекс покрывает две выборки - при указании как
обеих атрибутов Figure и Color, так и при указании только атрибута
Figure. Приведем пример применения такого покрытия:
n Data,id,ref
s Data("FigureColor","шарик","красный",1)=""
s Data("FigureColor","шарик","зеленый",2)=""
s Data("FigureColor","квадрат","красный",3)=""
s Data("FigureColor","квадрат","синий",4)=""
s Data("FigureColor","шарик","красный",5)=""
w "Select шарик + красный",!
s id=""
f s id=$o(Data("FigureColor","шарик","красный",id)) q:id="" d
. w id,!

3.4. СОСТАВНОЙ ИНДЕКС 235
w "Select шарик",!
s ref=$na(Data("FigureColor","шарик")) »
. w $qs(ref,4),!
q
f s ref=$q(@ref) q:ref="" d
Первая выборка выдает по условию по двум атрибутам, вторая - по
одному.
Использование и поддержка покрывающих индексов может быть как
очень эффективна по быстродействию и задействованию одного индекса
в нескольких задачах, так и может оказаться неэффективна в случае
катастрофического роста объема данных, занимаемого самим индексом
и фактическим обесцениванием кеширования базы данных. Фактически,
составной индекс является прямым конкурентом методу многоиндексной
выборки.
В случае если движок базы данных не умеет использовать многоиндексную выборку, то составному индексу альтернатив, конечно, нет. В
случае же возможности выбора следует оценить затраты на поддержку
составного индекса. При высокой кардинальности атрибутов составной
индекс, видимо, может оказаться менее эффективным, чем многоиндексная выборка по совокупным затратам.
Оценку затратности и предпочтительности разных вариантов лучше
производить в реальном проекте на реальных объемах данных, сопоставив с используемым аппаратным обеспечением. На общую оценку может
повлиять и общая использованная алгоритмика, и объем кеша, и объем
данных подлежащих индексированию, и объем получающихся в итоге
выборок.
Небольшой пример реализации составного индекса:
ind03 ; составной индекс по Figure м Color
q
CreateRecords()
k ^Index
k ^Data
n i,Figures,Colors,Counts,Figure,Color,Count,id
s Figures="квадрат~круг~отрезок~треугольник"
s Colors="красный~зелёный~синий~белый"
s Counts="2~5~12~8"
f i=1:1:12 d
. s Figure=$p(Figures,"~",$r(4)+1)
. s Color=$p(Colors,"~",$r(4)+1)
. s Count=$p(Counts,"~",$r(4)+1)
. s id=$$InsertRecord(Figure_"~"_Color_"~"_Count)
q
InsertRecord(RecordValues)

236 ГЛАВА 3. ИНДЕКСАЦИЯ ДАННЫХ
n id s id=$i(^Data)
l +^Data(id)
s ^Data(id)=RecordValues
d InsertIndexRecords(id,RecordValues)
l -^Data(id)
q id
DeleteRecord(id)
q:’$d(^Data(id))
l +^Data(id)
n RecordValues s RecordValues=$g(^Data(id))
d DeleteIndexRecords(id,RecordValues)
k ^Data(id)
l -^Data(id)
q
UpdateRecord(id,RecordValues)
q:’$d(^Data(id))
l +^Data(id)
n OldRecordValues s OldRecordValues=$g(^Data(id))
d DeleteIndexRecords(id,OldRecordValues)
s ^Data(id)=RecordValues
d InsertIndexRecords(id,RecordValues)
l -^Data(id)
q
InsertIndexRecords(id,RecordValues)
n Figure,Color
s Figure=$p((RecordValues),"~",1)
s Color=$p((RecordValues),"~",2)
l +^Index("FigureColor",Figure,Color,id)
s ^Index("FigureColor",Figure,Color,id)=""
l -^Index("FigureColor",Figure,Color,id)
q
DeleteIndexRecords(id,RecordValues)
n Figure,Color
s Figure=$p((RecordValues),"~",1)
s Color=$p((RecordValues),"~",2)
l +^Index("FigureColor",Figure,Color,id)
k ^Index("FigureColor",Figure,Color,id)
l -^Index("FigureColor",Figure,Color,id)
q
Здесь поддерживается только один составной индекс.
То, что индекс является составным, одновременно с тем не мешает
ему быть простым или кластерным. Эти возможности можно совмещать.
В приведенном примере показан простой составной индекс.
Можно также обратить внимание на то, что в индексных записях для
большого объема данных оказывается много записей, имеющих дублирующиеся фрагменты. В частности, могут совпадать следующие фрагменты

3.5. ПОКРЫВАЮЩИЙ ИНДЕКС 237
^Index("FigureColor",Figure,Color)
^Index("FigureColor",Figure)
^Index("FigureColor")
В практически всех MUMPS системах, в отличие от многих простых NoSQL систем, применяется компрессия ключей, и в большинстве
случаев такие дублирования фрагментов не приводят к какому-либо существенному росту объема индексов.
3.5 Покрывающий индекс
Покрывающим индексом (cover index) называется индекс, который может
быть использован для нескольких задач выборки данных, в том числе
для тех, для которых он изначально не планировался. Название отражает
не вид структуры, а различные возможности ее применения.
Индекс в силу своей структуры есть отображение значений атрибутов на идентификаторы записей. Поэтому содержит как набор значений
атрибутов, так и набор отображений. Практически любой индекс в силу
своего строения является покрывающим для по крайней мере нескольких
задач:
1. Поскольку содержит набор значений атрибутов, может быть использован для выборки списка различных имеющихся значений
атрибутов.
2. Поскольку каждое значение атрибута отображается на набор идентификаторов записей, можно найти записи по заданному значению.
3. Если значения атрибута находятся в некотором упорядочении, то
можно получить сортировку по значениям атрибутов в этом упорядочении.
4. Возможно определить, существует ли запись с заданным значением, и тогда можно реализовать ограничения различного рода,
накладываемые на данные. В частности, запрет иметь значение
"синий" более чем 5 записям одновременно.
Каждая возможность применения индекса вызвана некоторым отношением - либо внутри однородного набора, либо между значением и
набором. И, чем больше отношений содержится в индексе, тем больше
покрытий он обеспечивает. Например, пусть есть таблица с атрибутами Color и Figure. Составной индекс по Color и Figure покрывает уже
следующие задачи:

238 ГЛАВА 3. ИНДЕКСАЦИЯ ДАННЫХ
1. Выбрать набор различных значений Color
2. Выбрать по заданному Color идентификаторы записей (применять
вместо функции $O функцию $Q)
3. Выбрать по заданному Color и Figure идентификаторы записей
(применять функцию $O)
4. Отсортировать идентификаторы по Color и Figure ($O)
5. Выбрать идентификаторы для диапазона Color ($Q)
6. Выбрать идентификаторы для диапазона Figure при задании Color
($O)
7. Выбрать идентификаторы при задании диапазонов Color и Figure
($O по Color + вложенный $O по Figure)
8. Для заданного Color отсортировать по Figure.
При этом нужно отметить, что составной индекс по Color и Figure
уже не может быть использован, если условие наложено только на атрибут Figure. Поскольку в таком индексе значения Figure находятся в подчиненной, а не независимой иерархии по отношению к Color. Если необходимо использовать значения Figure независимо от значений Color, то
необходимо поддерживать второй индекс соответствующей структуры.
С точки зрения эффективности применение покрывающих индексов
вполне оправдано, поскольку одна индексная структура может быть использована многократно в различных задачах. При этом чем больше
атрибутов записи объединяет индекс, тем больше покрытий он обеспечивает. В случае применения межтабличных индексов эффективность
покрывающего свойства многократно увеличивается, поскольку позволяет сократить число операций соединений.
Приведем демонстрационный пример поддержания структуры данных
для записей с атрибутами Color и Figure, после чего приведем примеры
использования одного и того же индекса в различных задачах:
CreateRecords()
k ^Index
k ^Data
n i,Figures,Colors,Counts,Figure,Color,Count,id
s Figures="квадрат~круг~отрезок~треугольник"
s Colors="красный~зелёный~синий~белый"
s Counts="2~5~12~8"
f i=1:1:120 d

3.5. ПОКРЫВАЮЩИЙ ИНДЕКС 239
. s Figure=$p(Figures,"~",$r(4)+1)
. s Color=$p(Colors,"~",$r(4)+1)
. s Count=$p(Counts,"~",$r(4)+1)
. s id=$$InsertRecord(Figure_"~"_Color_"~"_Count)
q
InsertRecord(RecordValues)
n id s id=$i(^Data)
l +^Data(id)
s ^Data(id)=RecordValues
d InsertIndexRecords(id,RecordValues)
l -^Data(id)
q id
DeleteRecord(id)
q:’$d(^Data(id))
l +^Data(id)
n RecordValues s RecordValues=$g(^Data(id))
d DeleteIndexRecords(id,RecordValues)
k ^Data(id)
l -^Data(id)
q
UpdateRecord(id,RecordValues)
q:’$d(^Data(id))
l +^Data(id)
n OldRecordValues s OldRecordValues=$g(^Data(id))
d DeleteIndexRecords(id,OldRecordValues)
s ^Data(id)=RecordValues
d InsertIndexRecords(id,RecordValues)
l -^Data(id)
q
DeleteIndex(IndexName)
k ^Index(IndexName)
q
InsertIndexRecords(id,RecordValues)
d InsertIndexRecord("ColorFigure",id,
$p((RecordValues),"~",2),$p((RecordValues),"~",1))
q
DeleteIndexRecords(id,RecordValues)
d DeleteIndexRecord("ColorFigure",id,
$p((RecordValues),"~",2),$p((RecordValues),"~",1))
q
InsertIndexRecord(IndexName,id,ColorValue,FigureValue)
l +^Index(IndexName,ColorValue,FigureValue,id)
s ^Index(IndexName,ColorValue,FigureValue,id)=""
l -^Index(IndexName,ColorValue,FigureValue,id)
q
DeleteIndexRecord(IndexName,id,ColorValue,FigureValue)
l +^Index(IndexName,ColorValue,FigureValue,id)
k ^Index(IndexName,ColorValue,FigureValue,id)
l -^Index(IndexName,ColorValue,FigureValue,id)

240 ГЛАВА 3. ИНДЕКСАЦИЯ ДАННЫХ
q
Приведем несколько примеров таких выборок различного назначения
по одному и тому же индексу.
Выбрать набор различных значений Color
Select1()
n Color
s Color=""
f s Color=$o(^Index("ColorFigure",Color)) q:Color="" d
. w Color,!
q
Выбрать по заданному Color идентификаторы записей (применять
вместо функции $O функцию $Q)
Select2(Color="красный")
n ref
s ref=$na(^Index("ColorFigure",Color))
f s ref=$q(@ref) q:$s(ref="":1,$qs(ref,2)’=Color:1,1:0) d
. w $qs(ref,4),!
q
Выбрать по заданному Color и Figure идентификаторы записей (применять функцию $O)
Select3(Color="синий",Figure="квадрат")
n id
s id=""
f s id=$o(^Index("ColorFigure",Color,Figure,id)) q:id="" d
. w "Found id: "_id,!
q
Отсортировать идентификаторы по Color и Figure ($O)
Select4(COrder=1,FOrder=-1)
n c,f,id
s c="" f s c=$o(^Index("ColorFigure",c),COrder) q:c="" d
. s f="" f s f=$o(^Index("ColorFigure",c,f),FOrder) q:f="" d
. . s id="" f s id=$o(^Index("ColorFigure",c,f,id)) q:id="" d
. . . w c_" "_f_" "_id,!
q
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
