Download - Models for hierarchical data
![Page 1: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/1.jpg)
Models for Hierarchical Data with SQL and PHP
Bill Karwin, Percona Inc.
![Page 2: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/2.jpg)
www.percona.com
Me•Software developer•C, Java, Perl, PHP, Ruby•SQL maven•MySQL Consultant at Percona•Author of SQL Antipatterns:
Avoiding the Pitfalls of Database Programming
![Page 3: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/3.jpg)
www.percona.com
Problem
•Store & query hierarchical data- Categories/subcategories- Bill of materials- Threaded discussions
![Page 4: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/4.jpg)
www.percona.com
Example: Bug Report Comments
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 5: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/5.jpg)
www.percona.com
Solutions
•Adjacency list•Path enumeration•Nested sets•Closure table
![Page 6: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/6.jpg)
www.percona.com
Adjacency List
![Page 7: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/7.jpg)
www.percona.com
Adjacency List
•Naive solution nearly everyone uses •Each entry knows its immediate parent
comment_id parent_id author comment
1 NULL Fran What’s the cause of this bug?
2 1 Ollie I think it’s a null pointer.
3 2 Fran No, I checked for that.
4 1 Kukla We need to check valid input.
5 4 Ollie Yes, that’s a bug.
6 4 Fran Yes, please add a check
7 6 Kukla That fixed it.
![Page 8: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/8.jpg)
www.percona.com
Insert a New Node
INSERT INTO Comments (parent_id, author, comment) VALUES (5, ‘Fran’, ‘I agree!’);
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 9: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/9.jpg)
www.percona.com
Insert a New Node
INSERT INTO Comments (parent_id, author, comment) VALUES (5, ‘Fran’, ‘I agree!’);
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
(8) Fran: I agree!
![Page 10: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/10.jpg)
www.percona.com
Move a Node or Subtree
UPDATE Comments SET parent_id = 3 WHERE comment_id = 6;
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 11: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/11.jpg)
www.percona.com
Move a Node or Subtree
UPDATE Comments SET parent_id = 3 WHERE comment_id = 6;
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
![Page 12: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/12.jpg)
www.percona.com
Move a Node or Subtree
UPDATE Comments SET parent_id = 3 WHERE comment_id = 6;
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
![Page 13: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/13.jpg)
www.percona.com
Move a Node or Subtree
UPDATE Comments SET parent_id = 3 WHERE comment_id = 6;
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 14: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/14.jpg)
www.percona.com
Query Immediate Child/Parent
•Query a node’s children:SELECT * FROM Comments c1
LEFT JOIN Comments c2 ON (c2.parent_id = c1.comment_id);
•Query a node’s parent:SELECT * FROM Comments c1
JOIN Comments c2 ON (c1.parent_id = c2.comment_id);
![Page 15: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/15.jpg)
www.percona.com
Can’t Handle Deep TreesSELECT * FROM Comments c1
LEFT JOIN Comments c2 ON (c2.parent_id = c1.comment_id)LEFT JOIN Comments c3 ON (c3.parent_id = c2.comment_id)LEFT JOIN Comments c4 ON (c4.parent_id = c3.comment_id)LEFT JOIN Comments c5 ON (c5.parent_id = c4.comment_id) LEFT JOIN Comments c6 ON (c6.parent_id = c5.comment_id)LEFT JOIN Comments c7 ON (c7.parent_id = c6.comment_id)LEFT JOIN Comments c8 ON (c8.parent_id = c7.comment_id)LEFT JOIN Comments c9 ON (c9.parent_id = c8.comment_id)LEFT JOIN Comments c10 ON (c10.parent_id = c9.comment_id). . .
![Page 16: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/16.jpg)
www.percona.com
Can’t Handle Deep TreesSELECT * FROM Comments c1
LEFT JOIN Comments c2 ON (c2.parent_id = c1.comment_id)LEFT JOIN Comments c3 ON (c3.parent_id = c2.comment_id)LEFT JOIN Comments c4 ON (c4.parent_id = c3.comment_id)LEFT JOIN Comments c5 ON (c5.parent_id = c4.comment_id) LEFT JOIN Comments c6 ON (c6.parent_id = c5.comment_id)LEFT JOIN Comments c7 ON (c7.parent_id = c6.comment_id)LEFT JOIN Comments c8 ON (c8.parent_id = c7.comment_id)LEFT JOIN Comments c9 ON (c9.parent_id = c8.comment_id)LEFT JOIN Comments c10 ON (c10.parent_id = c9.comment_id). . .
it still doesn’t supportunlimited depth!
![Page 17: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/17.jpg)
www.percona.com
SQL-99 recursive syntaxWITH [RECURSIVE] CommentTree
(comment_id, bug_id, parent_id, author, comment, depth)AS ( SELECT *, 0 AS depth FROM Comments WHERE parent_id IS NULL UNION ALL SELECT c.*, ct.depth+1 AS depth FROM CommentTree ct JOIN Comments c ON (ct.comment_id = c.parent_id))SELECT * FROM CommentTree WHERE bug_id = 1234;
PostgreSQL, Oracle 11g, IBM DB2, Microsoft SQL Server, Apache Derby✓ ✗ MySQL, SQLite, Informix,
Firebird,etc.
![Page 18: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/18.jpg)
www.percona.com
Path Enumeration
![Page 19: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/19.jpg)
www.percona.com
Path Enumeration
•Store chain of ancestors in each node
comment_id path author comment
1 1/ Fran What’s the cause of this bug?
2 1/2/ Ollie I think it’s a null pointer.
3 1/2/3/ Fran No, I checked for that.
4 1/4/ Kukla We need to check valid input.
5 1/4/5/ Ollie Yes, that’s a bug.
6 1/4/6/ Fran Yes, please add a check
7 1/4/6/7/ Kukla That fixed it.
![Page 20: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/20.jpg)
www.percona.com
Path Enumeration
•Store chain of ancestors in each node
comment_id path author comment
1 1/ Fran What’s the cause of this bug?
2 1/2/ Ollie I think it’s a null pointer.
3 1/2/3/ Fran No, I checked for that.
4 1/4/ Kukla We need to check valid input.
5 1/4/5/ Ollie Yes, that’s a bug.
6 1/4/6/ Fran Yes, please add a check
7 1/4/6/7/ Kukla That fixed it.
good for breadcrumbs
![Page 21: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/21.jpg)
www.percona.com
Query Ancestors and Subtrees
•Query ancestors of comment #7:SELECT * FROM Comments
WHERE ‘1/4/6/7/’ LIKE path || ‘%’;
•Query descendants of comment #4:SELECT * FROM Comments
WHERE path LIKE ‘1/4/%’;
![Page 22: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/22.jpg)
www.percona.com
Add a New Child of #7INSERT INTO Comments (author, comment)
VALUES (‘Ollie’, ‘Good job!’);SELECT path FROM Comments
WHERE comment_id = 7;UPDATE Comments
SET path = $parent_path || LAST_INSERT_ID() || ‘/’ WHERE comment_id = LAST_INSERT_ID();
![Page 23: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/23.jpg)
www.percona.com
Nested Sets
![Page 24: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/24.jpg)
www.percona.com
Nested Sets
•Each comment encodes its descendantsusing two numbers:- A comment’s left number is less than all numbers
used by the comment’s descendants.- A comment’s right number is greater than all
numbers used by the comment’s descendants.- A comment’s numbers are between all
numbers used by the comment’s ancestors.
![Page 25: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/25.jpg)
www.percona.com
What Does This Look Like?
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 26: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/26.jpg)
www.percona.com
What Does This Look Like?
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
1
2
14
5
3 4
6 13
7 8 9 12
10 11
![Page 27: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/27.jpg)
www.percona.com
What Does This Look Like?
comment_id nsleft nsright author comment
1 1 14 Fran What’s the cause of this bug?
2 2 5 Ollie I think it’s a null pointer.
3 3 4 Fran No, I checked for that.
4 6 13 Kukla We need to check valid input.
5 7 8 Ollie Yes, that’s a bug.
6 9 12 Fran Yes, please add a check
7 10 11 Kukla That fixed it.
![Page 28: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/28.jpg)
www.percona.com
What Does This Look Like?
comment_id nsleft nsright author comment
1 1 14 Fran What’s the cause of this bug?
2 2 5 Ollie I think it’s a null pointer.
3 3 4 Fran No, I checked for that.
4 6 13 Kukla We need to check valid input.
5 7 8 Ollie Yes, that’s a bug.
6 9 12 Fran Yes, please add a check
7 10 11 Kukla That fixed it.
these are notforeign keys
![Page 29: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/29.jpg)
www.percona.com
Query Ancestors of #7
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
1
2
14
5
3 4
6 13
7 8 9 12
10 11
ancestors
child
![Page 30: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/30.jpg)
www.percona.com
Query Ancestors of #7
SELECT * FROM Comments child JOIN Comments ancestor ON child.nsleft BETWEEN ancestor.nsleft AND ancestor.nsrightWHERE child.comment_id = 7;
![Page 31: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/31.jpg)
www.percona.com
Query Subtree Under #4
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
1
2
14
5
3 4
6 13
7 8 9 12
10 11
parent
descendants
![Page 32: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/32.jpg)
www.percona.com
Query Subtree Under #4
SELECT * FROM Comments parent JOIN Comments descendant ON descendant.nsleft BETWEEN parent.nsleft AND parent.nsright WHERE parent.comment_id = 4;
![Page 33: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/33.jpg)
www.percona.com
Insert New Child of #5
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
1
2
14
5
3 4
6 13
7 8 9 12
10 11
![Page 34: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/34.jpg)
www.percona.com
Insert New Child of #5
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
1
2
14
5
3 4
6 13
7 8 9 12
10 11
10 11
12 13
14
15
16
![Page 35: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/35.jpg)
www.percona.com
Insert New Child of #5
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
1
2
14
5
3 4
6 13
7 8 9 12
10 11
(8) Fran: I agree!
8 9
10 11
12 13
14
15
16
![Page 36: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/36.jpg)
www.percona.com
Insert New Child of #5UPDATE Comments
SET nsleft = CASE WHEN nsleft >= 8 THEN nsleft+2 ELSE nsleft END, nsright = nsright+2 WHERE nsright >= 7;
INSERT INTO Comments (nsleft, nsright, author, comment) VALUES (8, 9, 'Fran', 'I agree!');
•Recalculate left values for all nodes to the right of the new child. Recalculate right values for all nodes above and to the right.
![Page 37: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/37.jpg)
www.percona.com
Query Immediate Parent of #6
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
1
2
14
5
3 4
6 13
7 8 9 12
10 11
![Page 38: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/38.jpg)
www.percona.com
Query Immediate Parent of #6
•Parent of #6 is an ancestor who has no descendant who is also an ancestor of #6.
SELECT parent.* FROM Comments AS c JOIN Comments AS parent ON (c.nsleft BETWEEN parent.nsleft AND parent.nsright) LEFT OUTER JOIN Comments AS in_between ON (c.nsleft BETWEEN in_between.nsleft AND in_between.nsright AND in_between.nsleft BETWEEN parent.nsleft AND parent.nsright) WHERE c.comment_id = 6 AND in_between.comment_id IS NULL;
![Page 39: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/39.jpg)
www.percona.com
Query Immediate Parent of #6
•Parent of #6 is an ancestor who has no descendant who is also an ancestor of #6.
SELECT parent.* FROM Comments AS c JOIN Comments AS parent ON (c.nsleft BETWEEN parent.nsleft AND parent.nsright) LEFT OUTER JOIN Comments AS in_between ON (c.nsleft BETWEEN in_between.nsleft AND in_between.nsright AND in_between.nsleft BETWEEN parent.nsleft AND parent.nsright) WHERE c.comment_id = 6 AND in_between.comment_id IS NULL;
querying immediate child is a similar problem
![Page 40: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/40.jpg)
www.percona.com
Closure Table
![Page 41: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/41.jpg)
www.percona.com
Closure Table
CREATE TABLE TreePaths ( ancestor INT NOT NULL, descendant INT NOT NULL, PRIMARY KEY (ancestor, descendant), FOREIGN KEY(ancestor) REFERENCES Comments(comment_id), FOREIGN KEY(descendant) REFERENCES Comments(comment_id));
![Page 42: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/42.jpg)
www.percona.com
Closure Table
•Many-to-many table•Stores every path from each node
to each of its descendants•A node even connects to itself
![Page 43: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/43.jpg)
www.percona.com
Closure Table illustration
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 44: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/44.jpg)
www.percona.com
Closure Table illustration
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 45: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/45.jpg)
www.percona.com
Closure Table illustration
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 46: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/46.jpg)
www.percona.com
Closure Table illustration
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 47: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/47.jpg)
www.percona.com
What Does This Look Like?
comment_id author comment
1 Fran What’s the cause of this bug?
2 Ollie I think it’s a null pointer.
3 Fran No, I checked for that.
4 Kukla We need to check valid input.
5 Ollie Yes, that’s a bug.
6 Fran Yes, please add a check
7 Kukla That fixed it.
ancestor descendant1 1
1 2
1 3
1 4
1 5
1 6
1 7
2 2
2 3
3 3
4 4
4 5
4 6
4 7
5 5
6 6
6 7
7 7
requires O(n²) rows
![Page 48: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/48.jpg)
www.percona.com
What Does This Look Like?
comment_id author comment
1 Fran What’s the cause of this bug?
2 Ollie I think it’s a null pointer.
3 Fran No, I checked for that.
4 Kukla We need to check valid input.
5 Ollie Yes, that’s a bug.
6 Fran Yes, please add a check
7 Kukla That fixed it.
ancestor descendant1 1
1 2
1 3
1 4
1 5
1 6
1 7
2 2
2 3
3 3
4 4
4 5
4 6
4 7
5 5
6 6
6 7
7 7
requires O(n²) rows
(but far fewer in practice)
![Page 49: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/49.jpg)
www.percona.com
Query Descendants of #4
SELECT c.* FROM Comments c JOIN TreePaths t ON (c.comment_id = t.descendant)WHERE t.ancestor = 4;
![Page 50: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/50.jpg)
www.percona.com
Paths Starting from #4
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 51: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/51.jpg)
www.percona.com
Query Ancestors of #6
SELECT c.* FROM Comments c JOIN TreePaths t ON (c.comment_id = t.ancestor)WHERE t.descendant = 6;
![Page 52: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/52.jpg)
www.percona.com
Paths Terminating at #6
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 53: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/53.jpg)
www.percona.com
Insert New Child of #5
INSERT INTO Comments VALUES (8, ‘Fran’, ‘I agree!’);
INSERT INTO TreePaths (ancestor, descendant)SELECT ancestor, 8 FROM TreePathsWHERE descendant = 5UNION ALL SELECT 8, 8;
![Page 54: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/54.jpg)
www.percona.com
Copy Paths from Parent
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
(8) Fran: I agree!
![Page 55: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/55.jpg)
www.percona.com
Copy Paths from Parent
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
(8) Fran: I agree!
![Page 56: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/56.jpg)
www.percona.com
Copy Paths from Parent
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
(8) Fran: I agree!
![Page 57: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/57.jpg)
www.percona.com
Delete Child #7
DELETE FROM TreePaths WHERE descendant = 7;
![Page 58: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/58.jpg)
www.percona.com
Delete Paths Terminating at #7
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 59: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/59.jpg)
www.percona.com
Delete Paths Terminating at #7
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 60: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/60.jpg)
www.percona.com
Delete Paths Terminating at #7
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
![Page 61: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/61.jpg)
www.percona.com
Delete Paths Terminating at #7
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 62: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/62.jpg)
www.percona.com
Delete Subtree Under #4
DELETE FROM TreePaths WHERE descendant IN (SELECT descendant FROM TreePaths WHERE ancestor = 4);
![Page 63: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/63.jpg)
www.percona.com
Delete Any Paths Under #4
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 64: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/64.jpg)
www.percona.com
Delete Any Paths Under #4
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 65: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/65.jpg)
www.percona.com
Delete Any Paths Under #4
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
![Page 66: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/66.jpg)
www.percona.com
Delete Any Paths Under #4
(1) Fran: What’s the cause of this bug?
(2) Ollie: I think it’s a null pointer.
(3) Fran: No, I checked for that.
(4) Kukla: We need to check valid input.
(5) Ollie: Yes, that’s a bug.
(6) Fran: Yes, please add a check.
(7) Kukla: That fixed it.
![Page 67: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/67.jpg)
www.percona.com
Path Length•Add a length column•MAX(length) is depth of tree•Makes it easier to query
immediate parent or child:SELECT c.*
FROM Comments cJOIN TreePaths t ON (c.comment_id = t.descendant)WHERE t.ancestor = 4 AND t.length = 1;
ancestor descendant length1 1 0
1 2 1
1 3 2
1 4 1
1 5 2
1 6 2
1 7 3
2 2 0
2 3 1
3 3 0
4 4 0
4 5 1
4 6 1
4 7 2
5 5 0
6 6 0
6 7 1
7 7 0
![Page 68: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/68.jpg)
www.percona.com
Path Length•Add a length column•MAX(length) is depth of tree•Makes it easier to query
immediate parent or child:SELECT c.*
FROM Comments cJOIN TreePaths t ON (c.comment_id = t.descendant)WHERE t.ancestor = 4 AND t.length = 1;
ancestor descendant length1 1 0
1 2 1
1 3 2
1 4 1
1 5 2
1 6 2
1 7 3
2 2 0
2 3 1
3 3 0
4 4 0
4 5 1
4 6 1
4 7 2
5 5 0
6 6 0
6 7 1
7 7 0
![Page 69: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/69.jpg)
www.percona.com
Choosing the Right Design
Design Tables Query Child
Query Subtree
Delete Node
Insert Node
Move Subtree
Referential Integrity
Adjacency List
1 Easy Hard Easy Easy Easy Yes
Path Enumeration
1 Hard Easy Easy Easy Easy No
Nested Sets 1 Hard Easy Hard Hard Hard No
Closure Table
2 Easy Easy Easy Easy Easy Yes
![Page 70: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/70.jpg)
www.percona.com
PHP Demo of Closure Table
![Page 71: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/71.jpg)
www.percona.com
Hierarchical Test Data
• Integrated Taxonomic Information System- http://itis.gov/- Free authoritative taxonomic information on plants,
animals, fungi, microbes - 518,756 scientific names (as of Feb 2011)
![Page 72: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/72.jpg)
www.percona.com
California PoppyKingdom: PlantaeDivision: TracheobiontaClass: MagnoliophytaOrder: Magnoliopsidaunranked: Magnoliidaeunranked: PapaveralesFamily: PapaveraceaeGenus: EschscholziaSpecies: Eschscholzia californica
![Page 73: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/73.jpg)
www.percona.com
California PoppyKingdom: PlantaeDivision: TracheobiontaClass: MagnoliophytaOrder: Magnoliopsidaunranked: Magnoliidaeunranked: PapaveralesFamily: PapaveraceaeGenus: EschscholziaSpecies: Eschscholzia californica
id=18956
![Page 74: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/74.jpg)
www.percona.com
California Poppy: ITIS Entry
SELECT * FROM Hierarchy WHERE hierarchy_string LIKE ‘%-18956’;
hierarchy_string202422-564824-18061-18063-18064-18879-18880-18954-18956
![Page 75: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/75.jpg)
www.percona.com
California Poppy: ITIS Entry
SELECT * FROM Hierarchy WHERE hierarchy_string LIKE ‘%-18956’;
hierarchy_string202422-564824-18061-18063-18064-18879-18880-18954-18956
ITIS data uses path enumeration
...but I converted it to closure table
![Page 76: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/76.jpg)
www.percona.com
Hierarchical Data Classesabstract class ZendX_Db_Table_TreeTable
extends Zend_Db_Table_Abstract{ public function fetchTreeByRoot($rootId, $expand) public function fetchBreadcrumbs($leafId)}
![Page 77: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/77.jpg)
www.percona.com
Hierarchical Data Classesclass ZendX_Db_Table_Row_TreeRow
extends Zend_Db_Table_Row_Abstract{ public function addChildRow($childRow) public function getChildren()}
class ZendX_Db_Table_Rowset_TreeRowset extends Zend_Db_Table_Rowset_Abstract{ public function append($row)}
![Page 78: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/78.jpg)
www.percona.com
Using TreeTableclass ItisTable extends ZendX_Db_Table_TreeTable
{ protected $_name = “longnames”; protected $_closureName = “treepaths”;}
$itis = new ItisTable();
![Page 79: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/79.jpg)
www.percona.com
Breadcrumbs$breadcrumbs = $itis->fetchBreadcrumbs(18956);foreach ($breadcrumbs as $crumb) {
print $crumb->completename . “ > ”;}
Plantae > Tracheobionta > Magnoliophyta > Magnoliopsida > Magnoliidae > Papaverales > Papaveraceae > Eschscholzia > Eschscholzia californica >
![Page 80: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/80.jpg)
www.percona.com
Breadcrumbs SQL
SELECT a.* FROM longnames AS a INNER JOIN treepaths AS c ON a.tsn = c.a WHERE (c.d = 18956) ORDER BY c.l DESC
![Page 81: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/81.jpg)
www.percona.com
How Does it Perform?
•Query profile = 0.0006 sec•MySQL EXPLAIN:
table type key ref rows extra
c ref tree_dl const 9 Using where; Using index
a eq_ref primary c.a 1
![Page 82: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/82.jpg)
www.percona.com
Dump Tree$tree = $itis->fetchTreeByRoot(18880); // Papaveraceaeprint_tree($tree);
function print_tree($tree, $prefix = ‘’){ print “{$prefix} {$tree->completename}\n”; foreach ($tree->getChildren() as $child) { print_tree($child, “{$prefix} ”); }}
![Page 83: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/83.jpg)
www.percona.com
Dump Tree Result Papaveraceae Platystigma Platystigma linearis Glaucium Glaucium corniculatum Glaucium flavum Chelidonium Chelidonium majus Bocconia Bocconia frutescens Stylophorum Stylophorum diphyllum Stylomecon Stylomecon heterophylla Canbya Canbya aurea Canbya candida Chlidonium Chlidonium majus
Romneya Romneya coulteri Romneya trichocalyx Dendromecon Dendromecon harfordii Dendromecon rigida Eschscholzia Eschscholzia californica Eschscholzia glyptosperma Eschscholzia hypecoides Eschscholzia lemmonii Eschscholzia lobbii Eschscholzia minutiflora Eschscholzia parishii Eschscholzia ramosa Eschscholzia rhombipetala Eschscholzia caespitosaetc...
![Page 84: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/84.jpg)
www.percona.com
Dump Tree SQL
SELECT d.*, p.a AS _parent FROM treepaths AS cINNER JOIN longnames AS d ON c.d = d.tsnLEFT JOIN treepaths AS p ON p.d = d.tsn AND p.a IN (202422, 564824, 18053, 18020) AND p.l = 1 WHERE (c.a = 202422) AND (p.a IS NOT NULL OR d.tsn = 202422) ORDER BY c.l, d.completename;
![Page 85: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/85.jpg)
www.percona.com
Dump Tree SQL
SELECT d.*, p.a AS _parent FROM treepaths AS cINNER JOIN longnames AS d ON c.d = d.tsnLEFT JOIN treepaths AS p ON p.d = d.tsn AND p.a IN (202422, 564824, 18053, 18020) AND p.l = 1 WHERE (c.a = 202422) AND (p.a IS NOT NULL OR d.tsn = 202422) ORDER BY c.l, d.completename;
show children of these nodes
![Page 86: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/86.jpg)
www.percona.com
How Does it Perform?
•Query profile = 0.20 sec on Macbook Pro•MySQL EXPLAIN:
table type key ref rows extra
c ref tree_adl const 114240 Using index; Using temporary; Using filesort
d eq_ref primary c.d 1
p ref tree_dl c.d, const
1 Using where; Using index
![Page 87: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/87.jpg)
www.percona.com
SHOW CREATE TABLECREATE TABLE `treepaths` (
`a` int(11) NOT NULL DEFAULT '0', `d` int(11) NOT NULL DEFAULT '0', `l` tinyint(3) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`a`,`d`), KEY `tree_adl` (`a`,`d`,`l`), KEY `tree_dl` (`d`,`l`), CONSTRAINT FOREIGN KEY (`a`) REFERENCES `longnames` (`tsn`), CONSTRAINT FOREIGN KEY (`d`) REFERENCES `longnames` (`tsn`)) ENGINE=InnoDB
![Page 88: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/88.jpg)
www.percona.com
SHOW TABLE STATUS
Name: treepathsEngine: InnoDBVersion: 10Row_format: CompactRows: 4600439Avg_row_length: 62Data_length: 288276480Max_data_length: 0Index_length: 273137664Data_free: 7340032
![Page 89: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/89.jpg)
www.percona.com
Demo Time!
![Page 90: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/90.jpg)
www.percona.com
SQL Antipatterns
http://www.pragprog.com/titles/bksqla/
![Page 91: Models for hierarchical data](https://reader034.vdocuments.mx/reader034/viewer/2022050903/540e0b808d7f72927e8b4acb/html5/thumbnails/91.jpg)
www.percona.com
License and Copyright
Copyright 2010-2013 Bill Karwinwww.slideshare.net/billkarwin
Released under a Creative Commons 3.0 License: http://creativecommons.org/licenses/by-nc-nd/3.0/
You are free to share - to copy, distribute and transmit this work, under the following conditions:
Attribution. You must attribute this work
to Bill Karwin.
Noncommercial. You may not use this work for commercial purposes.
No Derivative Works. You may not alter, transform,
or build upon this work.