Logo CitForum CITForum на CD Форумы Газета Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

22.05.2012

Google
WWW CITForum.ru
2001 г

Моделирование иерархических объектов

Виноградов С. А.
04.06.2001 г.

Введение

Многим структурам и объектам свойственна иерархичность. За примерами далеко ходить не надо. Почти все объекты состоят из частей, которые, в свою очередь, могут состоять из более мелких деталей. Общественные структуры, как правило, отражают жесткую иерархическую модель подчинения, сходящуюся к одному подразделению или человеку.

Из-за внешнего сходства, иерархические модели часто называют деревьями, вершину иерархии - корнем дерева, самые низшие ответвления - листьями.

По аналогии с поколениями человеческого рода, непосредственно более высокий уровень иерархии называют родителем, а все уровни, под которыми находиться текущий элемент, - его предками. Все элементы, находящиеся непосредственно под текущим называют его детьми, а вообще все, находящиеся под ним - потомками.

Иерархические структуры довольно часто приходиться моделировать в базах данных, при этом возникают некоторые, характерные только для иерархии, вопросы. Например, как узнать количество всех потомков у данного элемента, или, на каком уровне он находится, или, допустим, требуется получить список всех потомков заданного элемента, у которых нет детей. Попробуем получить ответы на эти и другие вопросы.

Простейшая иерархия

В качестве примера, возьмем часть схемы подразделений на предприятии:

A1
B1B2
C1C2C3

где А1 - подразделение верхнего уровня (возможно, не единственное на этом уровне),
В1 и В2 - входят в А1,
С1 - входит в В1, С2 и С3 - входят в В2.

Можно легко создать таблицу, которая содержит информацию об этих подразделениях (здесь идалее - синтаксис MS SQL):

create table Departments
(
Id int not null identity primary key,
Parent int not null references Departments(Id),
Name varchar(32) not null
)

Поле Parent является ссылкой на Id (первичный ключ) вышестоящего уровня в иерархии. В данном случае оно указывает, в какое подразделение входит каждый отдел.

Departments
Id Parent Name
1 0 A1
2 1 B1
3 1 B2
4 2 C1
5 3 C2
6 3 C3

Характерные вопросы

Пользуясь такой таблицей, легко можно найти родителя или детей у определенного элемента. Но обычно с иерархическими объектами возникают более сложные задачи.

Вероятно, мы захотим узнать, является ли данный элемент терминальным, то есть, отсутствуют ли другие элементы, входящие в него. Это нужно, например, для того, чтобы отличать такие элементы от нетерминальных при выводе иерархического справочника пользователю.

Также может потребоваться узнать, на каком уровне иерархии находится заданный элемент.

Может оказаться необходимым получить всех предков данного элемента, начиная сверху или снизу.

Часто бывает нужно получить всех потомков какого-нибудь элемента, при этом с разными условиями: например, только терминальных, или, находящихся только на определенном уровне и т. д.

Из приведенной выше схемы совсем не очевидны ответы на все эти вопросы. Конечно, если сервер базы данных специально поддерживает иерархию или допускает рекурсию в запросах, то большинство ответов можно получить одним запросом. В противном случае получение результатов будет крайне неэффективным. Как же организовать хранение иерархических объектов, чтобы легко и быстро получать ответы на перечисленные вопросы?

Обход дерева

Одно из решений было предложено Joe Celko (см. [1]). Он рекомендовал добавить в таблицу два дополнительных целочисленных поля: Left и Right, в которые заносятся результаты обхода дерева, начиная с корня. Обход организуется следующим образом: каждый раз, при прохождении какого-нибудь элемента указателем, счетчик увеличивается на единицу; при попадании в терминальный элемент, указатель возвращается в родителя и ищет следующего ребенка. В поле Left записывается значение счетчика при первом прохождении элемента, а в поле Right - при последнем. При таком варианте, наша таблица подразделений выглядела бы следующим образом:

create table Departments
(
Id int not null identity primary key,
Parent int not null references Departments(Id),
Name varchar(32) not null,
Left int not null,
Right int not null
)

Departments
Id Parent Name Left Right
1 0 A1 1 11
2 1 B1 2 4
3 1 B2 6 10
4 2 C1 3 3
5 3 C2 7 7
6 3 C3 9 9

Комбинируя эти поля и сравнивая их с такими же полями других элементов, такая схема позволяет получить ответы на все поставленные вопросы.

Терминальные элементы заметно сразу - у них Left = Right.

Отношения предок - потомок вычисляются тоже легко: Left потомка всегда больше чем у предка, а Right - меньше.

Информацию об уровне заданного элемента можно узнать, получив количество его предков.

Количество потомков = (Right - Left) / 2.

Главный недостаток этого решения в том, что при изменении в структуре дерева, приходится заново пересчитывать значения полей Left и Right во всей таблице. То есть, такой способ годится только для небольших, редко изменяемых таблиц.

Вспомогательная таблица

Более эффективный и удобный способ состоит в том, чтобы, в дополнение к первоначальной таблице, создать вспомогательную таблицу, содержащую всего два поля. В одном из них следует хранить Id элемента, а в другом - Id всех его предков.

create table DepartmentsAncestors
(
Department int not null references Departments(Id),
Ancestor int not null references Departments(Id)
constraint DepartmentAncestor primary key (Department, Ancestor)
)

Поле Ancestor ссылается на Id предка каждого элемента. В данном случае оно позволяет узнать все подразделения, в которые входит данный отдел.

DepartmentsAncestors
Department Ancestor
2 1
3 1
4 2
4 1
5 3
5 1
6 3
6 1

Подобная схема легко позволяет получить любую информацию об иерархических элементах одним запросом.

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

Информацию об уровне заданного элемента можно узнать, получив количество его предков.

Терминальность элемента можно узнать, пользуясь только основной таблицей - достаточно проверить, есть ли элементы, Parent которых равен Id текущего.

Модификация вспомогательной таблицы, при изменении основной, производится довольно просто. Заботу о ней можно предоставить либо триггерам, либо приложению.

Если запросы с использование информации об уровне и признаке терминальности встречаются часто, и требования к времени их выполнения высоки, то желательно создать соответствующие поля в основной таблице и поддерживать в них актуальные значения. Например:

create table Departments
(
Id int not null identity primary key,
Parent int not null references Departments(Id),
Name varchar(32) not null,
Level int not null,
Terminal bit not null defaul(1)
)

Departments
Id Parent Name Level Terminal
1 0 A1 1 0
2 1 B1 2 0
3 1 B2 2 0
4 2 C1 3 1
5 3 C2 3 1
6 3 C3 3 1

Пользуясь двумя такими таблицами, можно легко строить практически любые запросы, характерные для иерархических объектов.


Используемые источники

[1] Joe Celko "A Look at SQL Trees",
http://ib.demo.ru/DevInfo/DBMSTrees/9603d06.html
http://ib.demo.ru/DevInfo/DBMSTrees/9604d06.html
http://ib.demo.ru/DevInfo/DBMSTrees/9605d06.html

 

Подписка на новости CITForum.ru

Новые публикации:

19 мая

  • Прозрачный механизм удаленного обслуживания системных вызовов

  • Система моделирования Grid: реализация и возможности применения

    Газета:

    Майкл Стоунбрейкер:

  • Ошибки в системах баз данных, согласованность "в конечном счете" и теорема CAP

  • Дискуссия по поводу "NoSQL" не имеет никакого отношения к SQL

    29 апреля

  • Материалы конференции "Корпоративные Базы Данных-2010"

  • Разные облики технологии баз данных (отчет о конференции)

    14 апреля

  • MapReduce: внутри, снаружи или сбоку от параллельных СУБД?

  • Научные вызовы технологиям СУБД

    Обзоры журнала Computer:

    31 марта

  • Рационализация согласованности в "облаках": не платите за то, что вам не требуется

  • Взаимные блокировки в Oracle

  • Архитектура среды тестирования на основе моделей, построенная на базе компонентных технологий

  • Объектное представление XML-документов

    Газета:

  • Microsoft для российских разработчиков: практика с элементами фундаментальности

    10 марта

  • HadoopDB: архитектурный гибрид технологий MapReduce и СУБД для аналитических рабочих нагрузок

  • Классификация OLAP-систем вида xOLAP

  • BGP. Три внешних канала. Балансировка исходящего и входящего трафиков

    Газета:

  • Что мы знаем об iPhone 4G?

    17 февраля

  • MapReduce и параллельные СУБД: друзья или враги?

  • Объектно-ориентированное программирование в ограничениях: новый подход на основе декларативных языков моделирования данных

  • Системологический подход к декомпозиции в объектно-ориентированном анализе и проектировании программного обеспечения

    Газета:

  • Эволюция Wine

    3 февраля

  • Дом на песке

  • Реальное переосмысление "формальных методов"

  • Интервью с Найджелом Пендзом

    Газета:

  • iPad. Первый взгляд на долгожданный планшет от Apple

  • Я не верю в iPad

    20 января

  • SQL/MapReduce: практический подход к поддержке самоописываемых, полиморфных и параллелизуемых функций, определяемых пользователями

  • Данные на лету: как технология потокового SQL помогает преодолеть кризис

    Обзоры журнала Computer:

    2 декабря

  • Сергей Кузнецов. Год эпохи перемен в технологии баз данных

    18 ноября

  • Генерация тестовых программ для подсистемы управления памятью микропроцессора

  • Сравнительный анализ современных технологий разработки тестов для моделей аппаратного обеспечения

    Все публикации >>>


  • IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

    Информация для рекламодателей PR-акции, размещение рекламы — тел. +7 495 6608306, ICQ 232284597 Пресс-релизы — pr@citforum.ru
    Послать комментарий
    Информация для авторов

    Редакция раздаёт котят!

    Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
    Copyright © 1997-2000 CIT, © 2001-2009 CIT Forum
    Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...