SlideShare a Scribd company logo
Trees in RDBs
Древовидная структура в PostgreSQL. SQL CommonДревовидная структура в PostgreSQL. SQL Common
Table ExpressionTable Expression  
(Алексей Кутепов, (Алексей Кутепов, Revel Systems iPad POSRevel Systems iPad POS))
Древовидные структуры:
•
Категории/подкатегории;
•
Комментарии в соцсетях;
•
Датацентр/комната/сервер/клиент/сервис;
•
Организационная иерархия;
•
…
•
RESTfull API Resources as a Tree
Room 1 Room 2
Server 1 Server 2 Server 3 Server 4
Cluster 1 Cluster 2 Cluster 3 Cluster 4 Cluster 6Cluster 5
Подходы к хранению деревьев в RDB
• Adjacency List
id parent_id name
1 NULL Room 1
2 1 Server 1
3 1 Server 2
4 3 Cluster 3
Свойства Adjacency List:
•
Удобно вставлять элементы
•
Переносить поддерево
•
Легко получать непосредственных потомков/предков
•
Трудно получать поддерево (но если у вас PostgreSQL…)
INSERT INTO resources (parent_id, name) VALUES (2, ‘Cluster 1’);
UPDATE resources SET parent_id = 2 WHERE id=4;
SELECT * FROM resources r_left LEFT JOIN resources r_right
ON (r_left.id = r_right.parent);
WITH Queries. Common Table Expression (CTE)
•
В стандарте SQL-99
•
Поддеживается PosgreSQL, Oracle 11g, Microsoft SQL
Server, …
•
Не поддерживается MySQL, SQLLite
•
CTE вводит вспомогательный statement, который
можно представить как временную таблицу, которая
существует только для одного, последующего сразу за
ним запроса.
•
WITH RECURSIVE - Using RECURSIVE, a WITH query can refer to
its own output.
WITH RECURSIVE t(n) AS (
VALUES (1)
UNION ALL
SELECT n+1 FROM t WHERE n < 100
)
SELECT sum(n) FROM t;
“Note: Strictly speaking, this process is iteration not recursion,
but RECURSIVE is the terminology chosen by the SQL standards
committee.”
Свойства Adjacency List:
•
Легко получать поддерево используя CTE
WITH RECURSIVE resources_cte_tree(id, parent_id, name, depth) AS (
SELECT *, 0 AS depth FROM resources WHERE parent_id = 5
UNION ALL
SELECT r.*, rct.depth+1 AS depth FROM resources_cte_tree rct
JOIN resources ON (rct.id = resources.id)
)
SELECT * FROM resources_cte_tree;
•
Path Enumeration
id path name
1 /1 Room 1
2 /1/2 Server 1
3 /1/3 Server 2
4 /1/2/4 Cluster 3
Свойства Path Enumeration (Breadcrumbs thumbsup):
•
Легко вставлять элементы.
•
Легко получать непосредственных потомков/предков
•
Легко получать поддерево
•
Затратно перемещать поддерево
SELECT * FROM resources r_left LEFT JOIN resources r_right
ON (r_left.id = r_right.parent);
SELECT * FROM resources WHERE path LIKE ‘/room/1/%’;
INSERT INTO resources (name) VALUES (‘Rack ’) RETURNING id;
SELECT path as parent_path FROM resources WHERE id = 1;
UPDATE resources SET path = parent_path || ‘/’ || id;
Nested Sets
•
Каждый ресурс «кодирует» свои дочерние ресурсы 2
ключами-числами:
•
«Левое» число ресурса всегда меньше чем левое число его
потомков
•
«Правое» число ресурса всегда больше, чем «правое» число
его потомков
Id: 1
Room 1
Id: 2
Server 1
Id: 3
Server 2
Id: 4
Cluster 1
Id: 5
Cluster 2
Id: 6
Cluster 3
1 12
72 8 11
3 4 5 6 9 10
•
Nested Sets
id left_key right_key name
1 1 12 Room 1
2 2 7 Server 1
3 8 11 Server 2
4 3 4 Cluster 1
5 5 6 Cluster 2
6 9 10 Cluster 3
Свойства Nested Sets:
●
Легко получать поддерево потомков/предков
●
Трудно получить непосредственных предков/потомков (рецепт –
добавить поле parent_id и/или depth)
●
Трудно вставлять элемент
●
Трудно перемещать дерево
●
Можно хранить только одно дерево в одной таблице
SELECT id, name FROM resources WHERE left_key >= $left_key AND right_key 
<= $right_key ORDER BY left_key
SELECT id, name, level FROM  resources  WHERE left_key 
<= $left_key ANDright_key >= $right_key ORDER BY left_key
•
Closure Table (M2M)id name
1 Room 1
2 Server 1
3 Server 2
4 Cluster 1
5 Cluster 2
6 Cluster 3
7 Room 2
8 Server 3
9 Server 4
10 Cluster 4
11 Cluster 5
12 Cluster 6
id parent_id child_id
1 NULL 1
2 1 2
3 1 3
4 2 4
5 2 5
6 3 6
7 NULL 7
8 7 8
9 7 9
10 8 10
11 8 11
12 8 12
Room
1
Room
2
Server
1
Server
2
Server
3
Server
4
Cluster
1
Cluster
2
Cluster
3
Cluster
4
Cluster
6
Cluster
5
Свойства Closure Table
•
Легко запрашивать прямых потомков/предков
•
Легко вставлять новые элементы
•
Легко удалять элементы
•
Трудно запрашивать поддерево
SELECT r.* FROM resources r JOIN resources_tree t ON (r.id = t.child_id) 
WHERE r.id = 1;
SELECT r.* FROM resources r JOIN resources_tree t ON (r.id = t.parent_id) 
WHERE r.id = 1;
INSERT INTO resources (name) VALUES (‘Room 3’) RETURNING id;
INSERT INTO resources_tree (parent_id, child_id) VALUES (NULL, id);
DELETE FROM resources_tree WHERE parent_id = 1;
DELETE FROM resources WHERE id = 1;
Свойства Closure Table
•
Легко запрашивать поддерево SQL CTE (SQL Alchemy)
def get_subtree(root_id):
  tree_query = (
    db_base.db().query(Resource.id)
    .join(ResourcesTree,
          Resource.id == tree2resource_relation)
    .filter(ResourcesTree.parent_id == root_id)
    .cte(recursive=True)
  )
  tree_query = tree_query.union(
    db_base.db().query(Resource.id)
    .join(ResourcesTree, Resource.id == ResourcesTree.child_id)
    .join(tree_query, tree_query.c.id == ResourcesTree.parent_id)
  )
  return (db_base.db().query(models.Resource)
          .filter(tree_query.c.id == models.Resource.id))
Запрос прямых
потомков
Запрос
поддерева
Вставка нового
элемента
Изменение
поддерева
Adjacency List Легко Трудно* Легко Трудно
Path Enumeration Легко Легко Легко Трудно
Nested Sets Трудно** Легко Трудно Трудно
Closure Table Легко Трудно*** Легко Легко
* Легко, при использовании SQL CTE
** Легко, при введении полей parent_id и/или depth
*** Легко, при использовании SQL CTE, либо при добавлении ссылок к каждому потомку (не
всегда возможно)
Hierarchical and recursive queries in SQL
CONNECT BY is supported by EnterpriseDB,
Oracle database, CUBRID, IBM Informix
and DB2
Informative links:
Slides by Bill Karwin (of course):
http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back/
http://www.slideshare.net/billkarwin/models-for-hierarchical-data
Nested Sets:
http://www.getinfo.ru/article610.html
Closure Table:
https://habrahabr.ru/post/263629/
https://
en.wikipedia.org/wiki/Hierarchical_and_recursive_queries_in_SQL
Normative links:
https://
www.postgresql.org/docs/current/static/queries-with.html
SQL-99 standards between 1999-2002:
ISO/IEC 9075-1:1999
ISO/IEC 9075-2:1999
ISO/IEC 9075-5:1999

More Related Content

PPTX
Alasql - база данных SQL на JavaScript (MoscowJS)
PDF
"Alasql.js — база данных SQL на JavaScript" — Андрей Гершун, MoscowJS 18
PPTX
AlaSQL - SQL библиотека на JavaScript (выступление на PiterJS)
PPTX
18 Оттенков I18n
PPTX
PHP and database functionality
PDF
[2016 데이터 그랜드 컨퍼런스] 5 1(보안,품질). 웨어밸리 data security challenges and its solutio...
PDF
[2016 데이터 그랜드 컨퍼런스] 6 2(전략,솔루션). 큐브리드 오픈소스 dbms의 클라우드 구축 사례-발표자료
PPTX
跨平台開發從測試到架構
Alasql - база данных SQL на JavaScript (MoscowJS)
"Alasql.js — база данных SQL на JavaScript" — Андрей Гершун, MoscowJS 18
AlaSQL - SQL библиотека на JavaScript (выступление на PiterJS)
18 Оттенков I18n
PHP and database functionality
[2016 데이터 그랜드 컨퍼런스] 5 1(보안,품질). 웨어밸리 data security challenges and its solutio...
[2016 데이터 그랜드 컨퍼런스] 6 2(전략,솔루션). 큐브리드 오픈소스 dbms의 클라우드 구축 사례-발표자료
跨平台開發從測試到架構

Similar to Trees in RDBs (13)

PPTX
Вебинар Томулевича adjacency
PPTX
Oracle NoSQL Database
KEY
Objective-C 2.0: краткое описание языка и рантайма
PPT
Использование Sedna в WEB
PPTX
"AnnotatedSQL - провайдер с плюшками за 5 минут" - Геннадий Дубина, Senior So...
PPTX
Стажировка-2013, разработчики, занятие 11. Базы данных
PDF
Не все базы данных одинаково полезны
PDF
Выступление Сергея Аверина, Badoo, на High Performance Conference
PDF
Не все базы данных одинаково полезны
PDF
Расширенное кеширование в Doctrine2
PDF
Расширенное кеширование Doctrine2 (Ильяс Салихов, Intaro)
PDF
Все самые важные команды SQL за 60 минут
PPT
XML Native Database на примере SednaXML
Вебинар Томулевича adjacency
Oracle NoSQL Database
Objective-C 2.0: краткое описание языка и рантайма
Использование Sedna в WEB
"AnnotatedSQL - провайдер с плюшками за 5 минут" - Геннадий Дубина, Senior So...
Стажировка-2013, разработчики, занятие 11. Базы данных
Не все базы данных одинаково полезны
Выступление Сергея Аверина, Badoo, на High Performance Conference
Не все базы данных одинаково полезны
Расширенное кеширование в Doctrine2
Расширенное кеширование Doctrine2 (Ильяс Салихов, Intaro)
Все самые важные команды SQL за 60 минут
XML Native Database на примере SednaXML
Ad

Trees in RDBs

  • 2. Древовидная структура в PostgreSQL. SQL CommonДревовидная структура в PostgreSQL. SQL Common Table ExpressionTable Expression   (Алексей Кутепов, (Алексей Кутепов, Revel Systems iPad POSRevel Systems iPad POS))
  • 4. Room 1 Room 2 Server 1 Server 2 Server 3 Server 4 Cluster 1 Cluster 2 Cluster 3 Cluster 4 Cluster 6Cluster 5
  • 5. Подходы к хранению деревьев в RDB • Adjacency List id parent_id name 1 NULL Room 1 2 1 Server 1 3 1 Server 2 4 3 Cluster 3
  • 7. WITH Queries. Common Table Expression (CTE) • В стандарте SQL-99 • Поддеживается PosgreSQL, Oracle 11g, Microsoft SQL Server, … • Не поддерживается MySQL, SQLLite • CTE вводит вспомогательный statement, который можно представить как временную таблицу, которая существует только для одного, последующего сразу за ним запроса.
  • 8. • WITH RECURSIVE - Using RECURSIVE, a WITH query can refer to its own output. WITH RECURSIVE t(n) AS ( VALUES (1) UNION ALL SELECT n+1 FROM t WHERE n < 100 ) SELECT sum(n) FROM t; “Note: Strictly speaking, this process is iteration not recursion, but RECURSIVE is the terminology chosen by the SQL standards committee.”
  • 9. Свойства Adjacency List: • Легко получать поддерево используя CTE WITH RECURSIVE resources_cte_tree(id, parent_id, name, depth) AS ( SELECT *, 0 AS depth FROM resources WHERE parent_id = 5 UNION ALL SELECT r.*, rct.depth+1 AS depth FROM resources_cte_tree rct JOIN resources ON (rct.id = resources.id) ) SELECT * FROM resources_cte_tree;
  • 10. • Path Enumeration id path name 1 /1 Room 1 2 /1/2 Server 1 3 /1/3 Server 2 4 /1/2/4 Cluster 3
  • 11. Свойства Path Enumeration (Breadcrumbs thumbsup): • Легко вставлять элементы. • Легко получать непосредственных потомков/предков • Легко получать поддерево • Затратно перемещать поддерево SELECT * FROM resources r_left LEFT JOIN resources r_right ON (r_left.id = r_right.parent); SELECT * FROM resources WHERE path LIKE ‘/room/1/%’; INSERT INTO resources (name) VALUES (‘Rack ’) RETURNING id; SELECT path as parent_path FROM resources WHERE id = 1; UPDATE resources SET path = parent_path || ‘/’ || id;
  • 12. Nested Sets • Каждый ресурс «кодирует» свои дочерние ресурсы 2 ключами-числами: • «Левое» число ресурса всегда меньше чем левое число его потомков • «Правое» число ресурса всегда больше, чем «правое» число его потомков
  • 13. Id: 1 Room 1 Id: 2 Server 1 Id: 3 Server 2 Id: 4 Cluster 1 Id: 5 Cluster 2 Id: 6 Cluster 3 1 12 72 8 11 3 4 5 6 9 10
  • 14. • Nested Sets id left_key right_key name 1 1 12 Room 1 2 2 7 Server 1 3 8 11 Server 2 4 3 4 Cluster 1 5 5 6 Cluster 2 6 9 10 Cluster 3
  • 15. Свойства Nested Sets: ● Легко получать поддерево потомков/предков ● Трудно получить непосредственных предков/потомков (рецепт – добавить поле parent_id и/или depth) ● Трудно вставлять элемент ● Трудно перемещать дерево ● Можно хранить только одно дерево в одной таблице SELECT id, name FROM resources WHERE left_key >= $left_key AND right_key  <= $right_key ORDER BY left_key SELECT id, name, level FROM  resources  WHERE left_key  <= $left_key ANDright_key >= $right_key ORDER BY left_key
  • 16. • Closure Table (M2M)id name 1 Room 1 2 Server 1 3 Server 2 4 Cluster 1 5 Cluster 2 6 Cluster 3 7 Room 2 8 Server 3 9 Server 4 10 Cluster 4 11 Cluster 5 12 Cluster 6 id parent_id child_id 1 NULL 1 2 1 2 3 1 3 4 2 4 5 2 5 6 3 6 7 NULL 7 8 7 8 9 7 9 10 8 10 11 8 11 12 8 12 Room 1 Room 2 Server 1 Server 2 Server 3 Server 4 Cluster 1 Cluster 2 Cluster 3 Cluster 4 Cluster 6 Cluster 5
  • 17. Свойства Closure Table • Легко запрашивать прямых потомков/предков • Легко вставлять новые элементы • Легко удалять элементы • Трудно запрашивать поддерево SELECT r.* FROM resources r JOIN resources_tree t ON (r.id = t.child_id)  WHERE r.id = 1; SELECT r.* FROM resources r JOIN resources_tree t ON (r.id = t.parent_id)  WHERE r.id = 1; INSERT INTO resources (name) VALUES (‘Room 3’) RETURNING id; INSERT INTO resources_tree (parent_id, child_id) VALUES (NULL, id); DELETE FROM resources_tree WHERE parent_id = 1; DELETE FROM resources WHERE id = 1;
  • 18. Свойства Closure Table • Легко запрашивать поддерево SQL CTE (SQL Alchemy) def get_subtree(root_id):   tree_query = (     db_base.db().query(Resource.id)     .join(ResourcesTree,           Resource.id == tree2resource_relation)     .filter(ResourcesTree.parent_id == root_id)     .cte(recursive=True)   )   tree_query = tree_query.union(     db_base.db().query(Resource.id)     .join(ResourcesTree, Resource.id == ResourcesTree.child_id)     .join(tree_query, tree_query.c.id == ResourcesTree.parent_id)   )   return (db_base.db().query(models.Resource)           .filter(tree_query.c.id == models.Resource.id))
  • 19. Запрос прямых потомков Запрос поддерева Вставка нового элемента Изменение поддерева Adjacency List Легко Трудно* Легко Трудно Path Enumeration Легко Легко Легко Трудно Nested Sets Трудно** Легко Трудно Трудно Closure Table Легко Трудно*** Легко Легко * Легко, при использовании SQL CTE ** Легко, при введении полей parent_id и/или depth *** Легко, при использовании SQL CTE, либо при добавлении ссылок к каждому потомку (не всегда возможно)
  • 20. Hierarchical and recursive queries in SQL CONNECT BY is supported by EnterpriseDB, Oracle database, CUBRID, IBM Informix and DB2
  • 21. Informative links: Slides by Bill Karwin (of course): http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back/ http://www.slideshare.net/billkarwin/models-for-hierarchical-data Nested Sets: http://www.getinfo.ru/article610.html Closure Table: https://habrahabr.ru/post/263629/ https:// en.wikipedia.org/wiki/Hierarchical_and_recursive_queries_in_SQL
  • 22. Normative links: https:// www.postgresql.org/docs/current/static/queries-with.html SQL-99 standards between 1999-2002: ISO/IEC 9075-1:1999 ISO/IEC 9075-2:1999 ISO/IEC 9075-5:1999

Editor's Notes

  • #15: &amp;lt;номер&amp;gt;
  • #16: &amp;lt;номер&amp;gt;