Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

Trees in RDBs

312 visualizaciones

Publicado el

The story of one practical task.

Publicado en: Software
  • Inicia sesión para ver los comentarios

  • Sé el primero en recomendar esto

Trees in RDBs

  1. 1. Древовидная структура в PostgreSQL. SQL CommonДревовидная структура в PostgreSQL. SQL Common Table ExpressionTable Expression   (Алексей Кутепов, (Алексей Кутепов, Revel Systems iPad POSRevel Systems iPad POS))
  2. 2. Древовидные структуры: • Категории/подкатегории; • Комментарии в соцсетях; • Датацентр/комната/сервер/клиент/сервис; • Организационная иерархия; • … • RESTfull API Resources as a Tree
  3. 3. Room 1 Room 2 Server 1 Server 2 Server 3 Server 4 Cluster 1 Cluster 2 Cluster 3 Cluster 4 Cluster 6Cluster 5
  4. 4. Подходы к хранению деревьев в RDB • Adjacency List id parent_id name 1 NULL Room 1 2 1 Server 1 3 1 Server 2 4 3 Cluster 3
  5. 5. Свойства 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);
  6. 6. WITH Queries. Common Table Expression (CTE) • В стандарте SQL-99 • Поддеживается PosgreSQL, Oracle 11g, Microsoft SQL Server, … • Не поддерживается MySQL, SQLLite • CTE вводит вспомогательный statement, который можно представить как временную таблицу, которая существует только для одного, последующего сразу за ним запроса.
  7. 7. • 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.”
  8. 8. Свойства 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;
  9. 9. • 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
  10. 10. Свойства 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;
  11. 11. Nested Sets • Каждый ресурс «кодирует» свои дочерние ресурсы 2 ключами-числами: • «Левое» число ресурса всегда меньше чем левое число его потомков • «Правое» число ресурса всегда больше, чем «правое» число его потомков
  12. 12. 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
  13. 13. • 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
  14. 14. Свойства 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
  15. 15. • 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
  16. 16. Свойства 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;
  17. 17. Свойства 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))
  18. 18. Запрос прямых потомков Запрос поддерева Вставка нового элемента Изменение поддерева Adjacency List Легко Трудно* Легко Трудно Path Enumeration Легко Легко Легко Трудно Nested Sets Трудно** Легко Трудно Трудно Closure Table Легко Трудно*** Легко Легко * Легко, при использовании SQL CTE ** Легко, при введении полей parent_id и/или depth *** Легко, при использовании SQL CTE, либо при добавлении ссылок к каждому потомку (не всегда возможно)
  19. 19. Hierarchical and recursive queries in SQL CONNECT BY is supported by EnterpriseDB, Oracle database, CUBRID, IBM Informix and DB2
  20. 20. 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
  21. 21. 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

×