closure_tree icon indicating copy to clipboard operation
closure_tree copied to clipboard

join default_tree_scope only when a limit_depth is given

Open kakubin opened this issue 1 year ago • 1 comments

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.

kakubin avatar Oct 20 '24 03:10 kakubin