SlideShare une entreprise Scribd logo
1  sur  22
Древовидная структура в 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

Contenu connexe

Similaire à Trees in RDBs

Вебинар Томулевича adjacency
Вебинар Томулевича adjacencyВебинар Томулевича adjacency
Вебинар Томулевича adjacencyMedia Gorod
 
Oracle NoSQL Database
Oracle NoSQL DatabaseOracle NoSQL Database
Oracle NoSQL DatabaseAndrey Akulov
 
Objective-C 2.0: краткое описание языка и рантайма
Objective-C 2.0: краткое описание языка и рантаймаObjective-C 2.0: краткое описание языка и рантайма
Objective-C 2.0: краткое описание языка и рантаймаYandex
 
Использование Sedna в WEB
Использование Sedna в WEBИспользование Sedna в WEB
Использование Sedna в WEBAlexandre Kalendarev
 
"AnnotatedSQL - провайдер с плюшками за 5 минут" - Геннадий Дубина, Senior So...
"AnnotatedSQL - провайдер с плюшками за 5 минут" - Геннадий Дубина, Senior So..."AnnotatedSQL - провайдер с плюшками за 5 минут" - Геннадий Дубина, Senior So...
"AnnotatedSQL - провайдер с плюшками за 5 минут" - Геннадий Дубина, Senior So...Alex Tumanoff
 
Стажировка-2013, разработчики, занятие 11. Базы данных
Стажировка-2013, разработчики, занятие 11. Базы данныхСтажировка-2013, разработчики, занятие 11. Базы данных
Стажировка-2013, разработчики, занятие 11. Базы данных7bits
 
Выступление Сергея Аверина, Badoo, на High Performance Conference
Выступление Сергея Аверина, Badoo, на High Performance ConferenceВыступление Сергея Аверина, Badoo, на High Performance Conference
Выступление Сергея Аверина, Badoo, на High Performance ConferenceEYevseyeva
 
Не все базы данных одинаково полезны
Не все базы данных одинаково полезныНе все базы данных одинаково полезны
Не все базы данных одинаково полезныSergey Xek
 
Не все базы данных одинаково полезны
Не все базы данных одинаково полезныНе все базы данных одинаково полезны
Не все базы данных одинаково полезныSergey Xek
 
Расширенное кеширование в Doctrine2
Расширенное кеширование в Doctrine2Расширенное кеширование в Doctrine2
Расширенное кеширование в Doctrine2Ilyas Salikhov
 
Расширенное кеширование Doctrine2 (Ильяс Салихов, Intaro)
Расширенное кеширование Doctrine2 (Ильяс Салихов, Intaro)Расширенное кеширование Doctrine2 (Ильяс Салихов, Intaro)
Расширенное кеширование Doctrine2 (Ильяс Салихов, Intaro)Symfoniacs
 
Все самые важные команды SQL за 60 минут
Все самые важные команды SQL за 60 минутВсе самые важные команды SQL за 60 минут
Все самые важные команды SQL за 60 минутSkillFactory
 
XML Native Database на примере SednaXML
XML Native Database на примере SednaXMLXML Native Database на примере SednaXML
XML Native Database на примере SednaXMLSlach
 

Similaire à Trees in RDBs (13)

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

Trees in RDBs

  • 1.
  • 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

Notes de l'éditeur

  1. &amp;lt;номер&amp;gt;
  2. &amp;lt;номер&amp;gt;