Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

join default_tree_scope only when a limit_depth is given #440

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

kakubin
Copy link
Contributor

@kakubin kakubin commented Oct 20, 2024

Although the query issued by the closure_tree_class.has_tree call has an optional argument limit_depth to reduce the load, the cost remains excessively high when dealing with the hierarchy table containing huge amount of records. Below is the execution plan of the query.

MySQL [app_db]> EXPLAIN
SELECT
  `tags`.*
FROM
  `tags`
INNER JOIN `tag_hierarchies`
  ON `tags`.`id` = `tag_hierarchies`.`descendant_id`
INNER JOIN (
  SELECT
    descendant_id,
    MAX(generations) AS depth
  FROM
    `tag_hierarchies`
  GROUP BY
    descendant_id
) AS generation_depth
  ON `tags`.id = generation_depth.descendant_id
WHERE
  `tag_hierarchies`.`ancestor_id` = 2
  AND (
    `tags`.`id` != '2'
  )
ORDER BY
  `tag_hierarchies`.generations ASC,
  sort_order,
  generation_depth.depth;

+----+-------------+-----------------+------------+--------+-------------------------------+------------------+---------+--------------------------------------+---------+----------+----------------------------------------------+
| id | select_type | table           | partitions | type   | possible_keys                 | key              | key_len | ref                                  | rows    | filtered | Extra                                        |
+----+-------------+-----------------+------------+--------+-------------------------------+------------------+---------+--------------------------------------+---------+----------+----------------------------------------------+
|  1 | PRIMARY     | tag_hierarchies | NULL       | ref    | tag_anc_desc_idx,tag_desc_idx | tag_anc_desc_idx | 4       | const                                |      14 |   100.00 | Using index; Using temporary; Using filesort |
|  1 | PRIMARY     | tags            | NULL       | eq_ref | PRIMARY                       | PRIMARY          | 8       | app_db.tag_hierarchies.descendant_id |       1 |   100.00 | Using where                                  |
|  1 | PRIMARY     | <derived2>      | NULL       | ref    | <auto_key0>                   | <auto_key0>      | 4       | app_db.tags.id                       |      10 |   100.00 | Using where                                  |
|  2 | DERIVED     | tag_hierarchies | NULL       | index  | tag_anc_desc_idx,tag_desc_idx | tag_desc_idx     | 4       | NULL                                 | 970,482 |   100.00 | Using index                                  |
+----+-------------+-----------------+------------+--------+-------------------------------+------------------+---------+--------------------------------------+---------+----------+----------------------------------------------+
4 rows in set (0.003 sec)

The default_tree_scope is only meaningful when limit_depth is specified (though it's questionable whether it actually reduces the load). I have confirmed that even without the join, the load is not significantly higher.

Although the query issued by the closure_tree_class.has_tree call has an
optional argument `limit_depth` to reduce the load, the cost remains
excessively high when dealing with the hierarchy table containing huge
amount of records.
Below is the execution plan of the query.

```sql
MySQL [app_db]> EXPLAIN
SELECT
  `tags`.*
FROM
  `tags`
INNER JOIN `tag_hierarchies`
  ON `tags`.`id` = `tag_hierarchies`.`descendant_id`
INNER JOIN (
  SELECT
    descendant_id,
    MAX(generations) AS depth
  FROM
    `tag_hierarchies`
  GROUP BY
    descendant_id
) AS generation_depth
  ON `tags`.id = generation_depth.descendant_id
WHERE
  `tag_hierarchies`.`ancestor_id` = 2
  AND (
    `tags`.`id` != '2'
  )
ORDER BY
  `tag_hierarchies`.generations ASC,
  sort_order,
  generation_depth.depth;

+----+-------------+-----------------+------------+--------+-------------------------------+------------------+---------+--------------------------------------+---------+----------+----------------------------------------------+
| id | select_type | table           | partitions | type   | possible_keys                 | key              | key_len | ref                                  | rows    | filtered | Extra                                        |
+----+-------------+-----------------+------------+--------+-------------------------------+------------------+---------+--------------------------------------+---------+----------+----------------------------------------------+
|  1 | PRIMARY     | tag_hierarchies | NULL       | ref    | tag_anc_desc_idx,tag_desc_idx | tag_anc_desc_idx | 4       | const                                |      14 |   100.00 | Using index; Using temporary; Using filesort |
|  1 | PRIMARY     | tags            | NULL       | eq_ref | PRIMARY                       | PRIMARY          | 8       | app_db.tag_hierarchies.descendant_id |       1 |   100.00 | Using where                                  |
|  1 | PRIMARY     | <derived2>      | NULL       | ref    | <auto_key0>                   | <auto_key0>      | 4       | app_db.tags.id                       |      10 |   100.00 | Using where                                  |
|  2 | DERIVED     | tag_hierarchies | NULL       | index  | tag_anc_desc_idx,tag_desc_idx | tag_desc_idx     | 4       | NULL                                 | 970,482 |   100.00 | Using index                                  |
+----+-------------+-----------------+------------+--------+-------------------------------+------------------+---------+--------------------------------------+---------+----------+----------------------------------------------+
4 rows in set (0.003 sec)
```

The default_tree_scope is only meaningful when limit_depth is specified (though
it's questionable whether it actually reduces the load). I have confirmed that
even without the join, the load is not significantly higher.
@kakubin kakubin force-pushed the not_join_default_scope branch from 7210369 to b7df488 Compare November 3, 2024 14:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant