Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
MUMPS СУБД. Практика применения и опыт программирования.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
3.24. СОВМЕЩЕНИЕ ДРЕВОВИДНЫХ И БИТОВЫХ ИНДЕКСОВ311
s $bit(@name@(seg),pos)=’’bit q
Здесь по атрибуту Color строится обычный битовый индекс, а по атрибуту Figure простой древовидный. Теперь модернизируем алгоритм многоиндексной выборки таким образом, чтобы он использовал не пред­определенные операции $O(), $D(), $BIT(), а заданные извне имена функций. И составим сами функции, реализующие соответственно вы­борку следующего идентификатора и проверку существования иденти­фикатора.
Select(Figure,Color)
n res,names ; ставим функцию next и data для простого индекса s names(1,"next")="OrderSimple" s names(1,"data")="DataSimple" s names(1)=$na(^Index("Figure",Figure)) ; ставим функцию next и data для битового индекса s names(2,"next")="OrderBit" s names(2,"data")="DataBit" s names(2)=$na(^Index("Color",Color)) s names=2 d ANDvi($na(res),.names) s res="" f s res=$o(res(res)) q:res="" d . w res,! q
; ANDvi(ret,names) g ANDi+1 ANDi(ret,names...)
n id,i,j,place
s id="" f s i=1,id=$$ANDnexti() q:id="" s @ret@(id)=""
q ANDnexti() ANDrepi
s id=$$@names(i,"next")(names(i),id)
q:id="" ""
f j=i+1:1:i+names-1 s place=((j-1)#names)+1 »
i ’$$@names(place,"data")(names(place),id) s i=place g ANDrepi q id ;
#define BITSIZE (260000) OrderSimple(ref,id) q $o(@ref@(id)) DataSimple(ref,id) q $d(@ref@(id)) DataBit(ref,id) q $bitfind(@ref@(id\$$$BITSIZE),1,id#$$$BITSIZE+1)=(id#$$$BITSIZE+1) OrderBit(name,from)
n ret,seg,pos s ret=0 s from=+from s seg=from\$$$BITSIZE s pos=from#$$$BITSIZE+2
312 ГЛАВА 3. ИНДЕКСАЦИЯ ДАННЫХ
f s:(seg’="") ret=$bitfind(@name@(seg), »
1,pos) q:(ret)!(seg="") d . s seg=$o(@name@(seg)) q:seg="" . s pos=0 q:ret seg*$$$BITSIZE+ret-1 q ""
Здесь вызовы
$$@names(i,"next")(names(i),id) $$@names(place,"data")(names(place),id)
выполняют косвенный вызов метки по ее имени для выполнения необ­ходимых операций, абстрагируясь от действительного типа индекса.
Анализ показывает, что мы действительно справились с задачей сов­местить в одной выборке разноструктурные битовые и древовидные ин­дексы, и при этом количество избыточных операций увеличилось не на­много, а именно осталось в линейных пределах.
В действительности, нам здесь очень сильно помог тот факт, что би­товые индексы оперируют идентификаторами как натуральными числами (целыми и даже не отрицательными). Для них порядок арифметического следования совпадает с индексным упорядочением. Поэтому для обоих типов индексов удалось составить достаточно небольшое число абстрак­ций и легко и понятно их реализовать.
Для операции ИЛИ выборка из индекса сводится к простой опера­ции выборки идентификаторов по перечню индексов в одну структуру со слиянием. Результат также может быть по своей структуре как дре­вовидной, так и битовой структурой.
Операция вычитания может быть сделана как операция выборки пер­вого операнда в результирующую структуру, с последующей операцией выборки по второму операнду (вычитаемому), но вместо слияния выпол­няется удаление из результата.

3.25 Сортировка по индексу

В отличие от систем, имеющих встроенные специализированные меха­низмы сортировки строк, М-системы имеют единственную возможность произвести сортирование - это построить сортирующий индекс. Такие эк­зотические случаи, как сортировка фрагментов строки с разделителями, видимо, не будем относить к более-менее реальным случаям для мира баз данных с их объемами. Поскольку в М-системах определено един­ственное упорядочение - это индексная сортировка, то для построения
3.25. СОРТИРОВКА ПО ИНДЕКСУ 313
сортирующего индекса требуется введение промежуточной процедуры приведения сортируемых значений к соглашениям индексной сортиров­ки.
В индексной сортировке используется соглашение следования - если оба значения являются строковыми представлениями числа, то они срав­ниваются как числа в арифметическом упорядочении. Если не являются представлениями числа, то сортируются как строки побайтно. Если од­но значение является представлением числа, а другое нет, то числовое значение следует перед нечисловым. Кроме того, в большинстве реа­лизаций М-систем существует возможность тонкой настройки правила сортировки путем определения сортирующих таблиц. Для Cach´e это вы­полняет утилита nls. Для MiniM сортировка символов задается файлом определения символов (nat файл).
Сортирующий индекс может быть постоянным или временным - по­стоянный обычно используется для упорядоченной выборки постоянно хранимых данных, временный - для упорядоченной выборки временных данных, например, уже выбранных по какому-либо условию.
Временный сортирующий индекс, также как и постоянный, может быть организован в глобали в целях избежания переполнения локаль­ной памяти процесса. В этом случае, естественно, принимаются меры к различению данных между процессами, их использующими. Обычно в практике используется либо номер процесса либо условный очередной номер выборки.
Для сортировки значений атрибутов их следует либо приводить к числовому значению, либо к строковому. Операция приведения к сорти­рующему значению не обязательно обратима - это следует иметь ввиду при использовании сортирующего индекса для поиска. Также, в отли­чие от поискового индекса, сортирующий индекс зачастую логически сортирует сами объекты, а не значения атрибутов - используется вычис­ляемый атрибут, для которого задается функция возвращающая сорти­рующее значение. При этом сортирующее значение может зависеть от нескольких атрибутов.
Традиционным способом приведения к числовому сортирующему зна­чению является операция плюс - ее результат всегда числовое представ­ление значения или первой его части с отбрасыванием незначащей для интерпретации строки как числа. К числовым сортировкам относят как сами числовые величины, так и другие, которые могут быть трактованы в некотором условном числовом пространстве, например даты.
Более общей является строковая сортировка - путем приведения к строке можно сортировать составное значение. Традиционными сред­ствами приведения к строковой сортировке являются методы добавления
314 ГЛАВА 3. ИНДЕКСАЦИЯ ДАННЫХ
лидирующего пробела, использования непечатного символа в качестве внутреннего разделителя групп, приведение чисел к строковому пред­ставлению путем выравнивания разрядов, приведение к одному регистру, введение фиктивного поля со значением, производным от идентификато­ра строки.
Добавление лидирующего пробела приводит возможное числовое зна­чение атрибута к гарантированному строковому. Вместо пробела можно использовать любой символ, не являющийся цифрой - последующие за ним цифры будут сортироваться как строки.
Выравнивание числовых значений используется в сложной сортиров­ке для того, чтобы значение, будучи числовым, и сортируемым как стро­ка, тем не менее давало именно числовую сортировку - то есть при строковой сортировке порядок следования чисел должен сохраниться.
Для этого применяют обычно классические методы - выравнивание по ширине, дополнение незначащими лидирующими и завершающими нулями, проставление знака числа. Так же нормируются дробные числа, отдельно форматируются мантисса и отдельно порядок.
Приведем простой пример выравнивания чисел:
ViewSorted()
n a s a($$ToSortVal(-100))="" s a($$ToSortVal(-1.345))="" s a($$ToSortVal(-1.0))="" s a($$ToSortVal(-5.0))="" s a($$ToSortVal(0))="" s a($$ToSortVal(1.0))="" s a($$ToSortVal(1.345))="" s a($$ToSortVal(3.0))="" s a($$ToSortVal(100.5))="" w "Как значения легли в индексе",! zw a w "Как значения выбираются из индекса",! s a="" f s a=$o(a(a)) q:a="" d . ; удаляем лидирующие нули . n z s z=a f q:$e(z)’="0" s $e(z)="" . w +z,! q
ToSortVal(val)
n p1,p2 s p1=$p(val,".",1) s p1=$j(p1,10," ") s p1=$tr(p1," ","0") s p2=$p(val,".",2) s p2=$re($j($re(p2),10," ")) s p2=$tr(p2," ","0") q p1_"."_p2
3.25. СОРТИРОВКА ПО ИНДЕКСУ 315
здесь сортируемые значения приводятся к строкам, но при этом, сорти­руясь как строки они сортируются также как числа, сохраняя взаимное арифметическое упорядочение.
Это качество позволяет использовать такой фрагмент для соединения числа, приведенного к строковой сортировке, в качестве части строки для сложной сортировки, скажем одновременно по нескольким атрибутам, которая, безусловно, физически является строковой сортировкой.
Результат работы этого теста такой:
USER>d ViewSorted^indsort() Как значения легли в индексе a("000000-100.0000000000")="" a("00000000-1.0000000000")="" a("00000000-1.3450000000")="" a("00000000-5.0000000000")="" a("0000000000.0000000000")="" a("0000000001.0000000000")="" a("0000000001.3450000000")="" a("0000000003.0000000000")="" a("0000000100.5000000000")="" Как значения выбираются из индекса
-100
-1
-1.345
-5 0 1
1.345 3
100.5
Здесь отрицательные числа сортируются неправильно, и для ком­пенсации такого эффекта необходимо приведение всех чисел к положи­тельным путем прибавления константы к сортируемому значению для получения сортирующего:
ViewSorted()
n a s a($$ToSortVal(-100))="" s a($$ToSortVal(-1.345))="" s a($$ToSortVal(-1.0))="" s a($$ToSortVal(-5.0))="" s a($$ToSortVal(0))="" s a($$ToSortVal(1.0))="" s a($$ToSortVal(1.345))="" s a($$ToSortVal(3.0))="" s a($$ToSortVal(100.5))=""
316 ГЛАВА 3. ИНДЕКСАЦИЯ ДАННЫХ
w "Как значения легли в индексе",! zw a w "Как значения выбираются из индекса",! s a="" f s a=$o(a(a)) q:a="" d . ; удаляем лидирующие нули . n z s z=a-1000000000 f q:$e(z)’="0" s $e(z)="" . w +z,! q
ToSortVal(val)
n p1,p2 s val=val+1000000000 s p1=$p(val,".",1) s p1=$j(p1,10," ") s p1=$tr(p1," ","0") s p2=$p(val,".",2) s p2=$re($j($re(p2),10," ")) s p2=$tr(p2," ","0") q p1_"."_p2
Здесь значение 1000000000 было использовано в качестве сортиру­ющего дополнения, и эта величина существенно зависит от характера данных. В реальных случаях выбору величины дополнения необходимо уделять особое внимание.
Теперь, после применения дополнения, результат работы правильный, и числовое значение приведено к строковой сортировке, включая как положительные, так и отрицательные величины.
USER>d ViewSorted^indsort() Как значения легли в индексе a("0999999900.0000000000")="" a("0999999995.0000000000")="" a("0999999998.6550000000")="" a("0999999999.0000000000")="" a("1000000000.0000000000")="" a("1000000001.0000000000")="" a("1000000001.3450000000")="" a("1000000003.0000000000")="" a("1000000100.5000000000")="" Как значения выбираются из индекса
-100
-5
-1.345
-1 0 1
1.345 3
100.5
Отметим, что аналогичным способом отображения чисел из одного множества в другое но уже с требуемыми сортирующими свойствами
3.25. СОРТИРОВКА ПО ИНДЕКСУ 317
используют также для дат. Стандартно в М дату используют в формате $H, но это число, и для приведения к строковой сортировке используют замену, например в виде функции $zdt($h,8) в Cach´e. Это дает приве­дение даты и времени к замечательно сортирующемуся виду в фиксиро­ванном формате
"YYYYMMDD HH:MM:SS"
В таком виде использовать дату в качестве части сортирующей стро-
ки даже вполне читабельно при отладке.
Введение непечатного символа позволяет ввести в сортировку прави­ло разбиения на группы - до непечатного символа значения сортируются в рамках одной группы, после - в рамках подгруппы группы. Естествен­ными причинами введения групп являются иерархические отношения
- для упорядочения, скажем, номеров субсчетов в рамках субсчета, в который они сами входят. В качестве непечатных символов используют символы меньшие пробела. Это гарантирует, что сортирующий механизм MUMPS системы будет считать более короткие группы сортирующими­ся перед более длинными. При необходимости каждая из групп также может приводиться к фиксированному по длине форматированию.
Важным моментом сортировки является случай совпадения сорти­рующей последовательности для различных объектов. В этом случае следует либо ввести фиктивную группу со значением, производным от идентификатора объекта, либо строить дополнительный подиндекс.
Например, пусть есть два объекта
^Data(1)="Белый~Волк" ^Data(2)="Белый~Гусь"
здесь при сортировке следует выбрать либо вариант групп, либо вариант подиндекса.
Первый вариант, с применением групп:
структура:
^sort(цвет_$C(1)_идентиифкатор)=""
пример данных:
^sort("Белый"_$С(1)_"1")="" ^sort("Белый"_$С(1)_"2")=""
Второй вариант, с применением подиндекса:
структура:
^sort(Цвет,идентификатор)=""
пример данных:
^sort("Белый",1)="" ^sort("Белый",2)=""
318 ГЛАВА 3. ИНДЕКСАЦИЯ ДАННЫХ
При этом для выборки следует использовать в первом случае проход по $O() и получать значение искомого идентификатора функцией $P(), а во втором - проход по $Q() и получение искомого идентификатора функцией $QS().
Нужно помнить, то способ сортирования объектов полностью опре­деляется функцией получения сортирующего значения. При ее формиро­вании следует быть особенно внимательным и обеспечить правильность ее работы.

3.26 Статистики и кардинальность

Статистики индексов и кардинальность атрибутов - это числовые ха­рактеристики индексов и записей данных, помогающие автоматическому оптимизатору запроса выбрать наиболее оптимальный план выполнения этого запроса. В собственно самих MUMPS системах нет механизма оп­тимизатора, встроенных операций с индексами и выполнение програм­мы полностью определяется программистом. Поэтому далее речь идет об условном оптимизаторе, который может быть выполнен программно, либо разработчик может определить стратегии самостоятельно.
Кардинальностью атрибута называется количество его различных зна­чений. Скажем, у атрибута "пол" значений может быть всего три - муж­ской, женский и не указан. Поэтому при среднестатистической выборке по этому индексу СУБД фактически вернет треть таблицы. Если требу­ется сузить результат и есть возможность использовать иной план, то лучше его также оценить и выбрать лучший. Если же значением атрибу­та является дата, то, скажем, если в таблице за год сделать выборку на указанную дату, то СУБД вернет примерно одну трехсотую часть табли­цы. Конечно, во втором случае кардинальность выше и избирательность индекса по атрибуту дата намного лучше, чем по атрибуту пол. Иными словами, при выборке по высококардинальному атрибуту производится большее отсечение данных, чем при выборке по низкокардинальному.
Статистиками индекса называются внутренние дежурные данные, ко­торые ведет (или может вести и поддерживать по различным страте­гиям) СУБД, и в которых отражается статистическая информация по индексам. Большинство СУБД поддерживают гистограммные или более сложные статистики. В этих дежурных данных движок СУБД запоми­нает избирательность индекса вообще, избирательность отдельных зна­чений (несмотря на то, что может быть много различных дат, одна из них может быть у больше чем половины записей), частота использо­вания этого индекса и относительная эффективность его кеширования,
3.26. СТАТИСТИКИ И КАРДИНАЛЬНОСТЬ 319
объем загружаемых с диска данных при использовании этого индекса, относительная производительность операций при использовании индекса определенной структуры, и многое другое.
Реальная работа оптимизатора и устройство статистик зачастую пол­ностью производителями СУБД не раскрываются, зачастую составляют предмет гордости производителя и предмет особого внимания, поскольку именно эта часть наиболее уязвима при сравнении систем по скорости выполнения запросов и чувствительна к изменению как характера дан­ных, так и настроек сервера. Но для администраторов предоставляются дополнительные административные средства поддержки не только ин­дексов, но и их статистик. Если наличие статистик по отношению к таблицам является средством оптимизации доступа, то статистики по отношению к индексам являются средством оптимизации доступа к са­мим индексам.
Зачастую полноценная статистическая информация для своей под­держки может требовать колоссальных расходов - изменение одной лишь записи данных может повлиять на многие числовые характеристики, большинство из которых могут быть составлены как интегральные. При этом для обновления статистик в живую, на работающей базе, может понадобиться гораздо большая вычислительная мощность, чем на под­держание собственно самих обслуживаемых данных.
Для того, чтобы не перегружать сервер избыточными рассчетами ста­тистик, большинство СУБД имеют отдельно запускаемую утилиту об­новления статистик. При этом штатным режимом сервера является ра­бота некоторое время в режиме неизменных статистик и периодическое их перестроение. При работе в режиме необновления статистик опти­мизатор полагается на частично устаревшие данные и может выбрать неоптимальный план исполнения, хотя в большинстве случаев статисти­ки отражают ситуацию относительно адекватно. Обычно уже небольшая часть записей может приблизительно охарактеризовать и характер рас­пределения последующих данных.
Многим администраторам и программистам известна ситуация, ко­гда сервер с автоматичесим определением плана запроса начинает су­щественно снижать производительность, хотя на первый взгляд ничего странного с ним не сделали. Во многих случаях это именно проявле­ние неактуальности статистик индексов - планы выполнения запросов выбираются на основании неактуальных данных. Для исправления та­кой ситуации рекомендуется периодически запускать утилиту обновле­ния статистик - или вручную, или вносить ее исполнение в регламент автоматической работы сервера.
При использовании MUMPS систем программисты, используя пря-
320 ГЛАВА 3. ИНДЕКСАЦИЯ ДАННЫХ
мой доступ, никогда не сталкиваются с проявлением автоматического оптимизатора за его отсутствием. Но для создания общей картины при­ведем пример, в котором может проявиться работа оптимизатора в дру­гих СУБД либо если он выполнен в прикладной программе. Или, по крайней мере, проиллюстрировать его макет.
Пусть есть схема из двух таблиц - документ и строка документа. В документе пусть есть атрибуты дата, номер и название. У строки документа пусть есть порядковый номер, название изделия и количество. В задаче требуется выполнить выборку таких документов, на которые наложены условия:
1. Документы имеют заданную дату.
2. В строках документа используется заданное изделие.
Для реализации мы делаем две таблицы - одну для документа и вторую для строк документа. При этом вторая имеет ссылочный ключ на первую. Кроме того, поскольку в условии выборки фигурирует дата документа, то мы хотим использовать индекс на атрибут дата документа, и создаем его. Кроме того, по тем же соображениям создаем индекс по полю изделие у таблицы строк документов. Для поддержания ссылочной целостности поддерживаем индекс на атрибут - внешний ключ строки документа на документ.
Для реализации запроса у нас есть на выбор по меньшей мере два плана:
1. По индексу на дату документа выбрать подходящие документы и получить набор строк документа. Используя этот набор и индекс на ссылочный ключ строк документа, и второй индекс по атрибуту изделия строк документа, используя операцию пересечения мно­жеств, получить набор ссылочных ключей строк документа. Это будет набор идентификаторов документов.
2. Используя индекс по атрибуту изделия строк документа, получить набор строк документа. Используя набор идентификаторов доку­ментов и индекс по атрибуту даты документа и используя операцию пересечения множеств, получить набор идентификаторов докумен­тов.
Стоит вопрос - какой из двух этих планов выполнения выбрать. Авто-
матический оптимизатор может использовать кардинальность индексов