Базы данных

Иерархические данные

Что требуется

  • Хранение леса подвешенных деревьев
  • Элементы одного типа

Операции

Содержание

Базовые представления

  • Узлы
    • Forest(Id, Data)
  • Ребёнок-родитель
    • Parents(Id, PId)
  • Наследник-предок
    • Ancestors(Id, AId)

Навигационные запросы

  • Родитель?
    • select PId from Parents where Id = :Id;
      
  • Дети?
    • select Id from Parents where PId = :Id;
      
  • Предки?
    • select AId from Ancestors where Id = :Id;
      
  • Потомки?
    • select Id from Ancestors where AId = :Id;
      

Пути

  • Путь к предку?
    • select AId from Ancestors
      where Id = :Id and
          AId not in (select AId from Ancestors where Id = :AId)
      
  • Общие предки?
    • select AId from Ancestors where Id in (:Id1, :Id2)
      group by AId having count(Id) = 2
      
  • Путь между узлами?
    • select AId from Ancestors where Id in (:Id1, :Id2)
      group by AId having count(Id) = 1
      

Предикаты

  • Корни?
    • select Id from Forest where
          Id not in (select Id from Ancestors)
      
    • select Id from Forest where
          Id not in (select Id from Parents)
      
  • Листы?
    • select Id from Forest where
          Id not in (select AId from Ancestors)
      
    • select Id from Forest where Id
          not in (select PId from Parents)
      

Статистика

  • Глубины узлов?
    • select Id, count(AId) as depth
      from Forest natural join Ancestors
      group by Id
      
  • Глубины поддеревьев?
    • select AId, max(depth) as depth
      from Ancestors natural join Forest
      group by AId
      

Упорядочивание

  • Порядок на детях
    • Неупорядоченные деревья
    • Упорядоченные деревья
  • Порядок на результате
    • Inorder
    • Удобно при выводе в виде дерева

Обновление

  • Добавление корня
  • Добавление листа
  • Удаление листа
  • Удаление поддерева
  • Перемещение поддерева

Модель близости

Содержание

Описание

  • Ссылка на предка

Модель близости

  • Представление данных
    • Храним предка узла
  • Представление в базе данных
    • create table Forest (
          Id int not null primary key,
          PId int references Forest(Id),
          Data ...
      );
      
  • Как описать корень?
    • PId == null или PId == Id

Ребёнок-родитель

  • Как получить?
    • create view Parents(Id, PId, Data) as
      select Id, PId, Data 
      from Forest where PId is not null
      
    • create view Parents(Id, PId, Data) as
      select Id, PId, Data
      from Forest where PId <> Id
      

Наследник-предок

  • Как получить?
    • create view Ancestors(Id, AId) as
      with recursive Anc(Id, AId) as
          select Id, PId from Forest
          union 
          select Forest.Id, Ancestors.AId
            from Anc inner join Forest
               on Forest.PId = Ancestors.Id;
      select Id, AId 
      from Anc
      

Вставка

  • Добавление корня?
    • insert into Forest (Id, PId, Data)
      values (:Id, null, ...)
      
      insert into Forest (Id, PId, Data)
      values (:Id, :Id, ...)
      
  • Добавление листа?
    • insert into Forest (Id, PId, Data)
      values (:Id, :PId, ...)
      

Удаление и перемещение

  • Удаление листа?
    • delete from Forest where Id = :Id
      
  • Удаление поддерева?
    • delete from Forest where Id = :Id
          or Id in (select Id from Ancestors where AId = :Id)
      
  • Перемещение поддерева?
    • update Forest set PId = :Id where Id = :Id
      

Упорядочивание

  • Порядок на детях?
    • Добавить поле index
  • Как упорядочить результаты?
    • Страшная боль

Характеристики

  • Плюсы
    • Мало данных
    • Простота обновлений
  • Минусы
    • Рекурсивные запросы
    • Нет упорядочивания

Вложенные множества

Содержание

Описание

  • Времена входа и выхода в эйлеровом обходе

Представление

  • Обход дерева в глубину
    • Время входа
    • Время выхода
  • Представление в базе данных
    • create table Forest (
          Id int not null primary key,
          L int not null unique,
          R int not null unique,
          Data ...,
          constraint ordered check (L < R)
      );
      

Наследник-предок

  • Как получить?
    • create view Ancestors(Id, AId) as
      select D.Id, A.Id
      from Forest D, Forest A
      where D.L between A.L and A.R
      

Ребёнок-родитель

  • Как получить?
    • create view Parents(Id, PId) as
      select C.Id, P.Id
      from Forest C, Forest P
      where C.L between P.L and P.R 
          and not exists
              (select * from Forest I
                  where I.L between P.L and P.R
                     and C.L between I.L and I.R)
      

Вставка

  • Добавление корня?
    • select max(R) into m from Forest;
      insert into Forest (Id, L, R, Data)
          values (:Id, m + 1, m + 2, ...)
      
  • Добавление листа?
    • select R in rr from Forest where Id = :PId;
      update Forest set L = L + 2 where L >= rr;
      update Forest set R = R + 2 where R > = rr;
      insert into Forest (Id, L, R, Data)
          values (:Id, rr, rr + 1, ...);
      

Удаление

  • Удаление листа?
    • select R into rr from Forest where Id = :Id;
      update Forest set L = L - 2 where L > rr;
      update Forest set R = R - 2 where R > rr;
      delete from Forest where Id = :Id
      
  • Удаление поддерева?
    • select L into ll, R into rr from Forest where Id = :Id;
      delete from Forest where L between ll and rr
      update Forest set L = L - (rr - ll + 1) where L > rr;
      update Forest set R = R - (rr - ll + 1) where R > rr;
      

Перемещение поддерева

  • Как сделать?
    • Что и куда вставляем
    • Перенести в бесконечность
    • Переместить середину
    • Переместить на место

Ускорение

  • Как можно ускорить изменения?
    • Разреженные деревья
    • Проблемы с поддержкой разрежения
      • Вставка узлов разной глубины
    • Ленивая поддержка разрежения
      • Переразрежение части дерева

Упорядочивание

  • Порядок на детях?
    • Уже есть
  • Как упорядочить результаты?
    • order by L

Характеристики

  • Плюсы
    • Мало данных
    • Упорядочивание
    • Хорошая работа с индексами
  • Минусы
    • Сложность обновлений
    • Обновление за $O(n)$ или разреженные деревья

Модель путей

Содержание

Описание

  • Храним путь от корня

Представление

  • Составные идентификаторы пути
    • $l_1.l_2.l_3...l_k$
  • Представление в базе данных
    • create table Forest (
          Id int not null primary key,
          Path varchar(100) unique,
          Data ...
      );
      
    • Фиксированная длина меток l
    • Операции на строках: like, replace

Наследник-предок

  • Как получить?
    • create view Ancestors(Id, AId) as
      select D.Id, A.Id
      from Forest D, Forest A
      where A.Path like (D.Path || '.%')
      

Ребёнок-родитель

  • Как получить?
    • create view child(Id, AId) as
      select C.Id, P.Id
      from Forest C, Forest P
      where P.Path like (C.Path || '.%') and
          length(P.Path) + L + 1 = length(C.Path)
      

Вставка

  • Добавление корня?
    • insert into Forest (Id, Path, Data)
      values (:Id, :Label, ...)
      
  • Добавление листа?
    • insert into Forest (Id, PPath, Data)
      values (:Id, :PPath || '.' || :Label, ...)
      
    • insert into Forest (Id, Path, Data)
      values (
          :Id,
          (select Path from Forest where Id = :PId) || '.' || :Label,
          ...
      )
      

Удаление и перемещение

  • Удаление листа?
    • delete from Forest where Id = :Id
      
  • Удаление поддерева?
    • delete from Forest 
      where Path like 
          ((select Path from Forest where Id = :Id) || ".%")
      
  • Перемещение поддерева?
    • Заменить префиксы путей себе и потомкам

Упорядочивание

  • Порядок на детях?
    • По увеличению меток
  • Как упорядочить результаты?
    • order by Path

Характеристики

  • Плюсы
    • Упорядочивание
    • Простой поиск детей и потомков
    • Простота обновлений
  • Минусы
    • Ограничение глубины
    • $O(n^2)$ данных для глубоких деревьев
    • Индексы на строках

Литература

Содержание

Основная литература