My table (projects):
id, lft, rgt
1, 1, 6
2, 2, 3
3, 4, 5
4, 7, 10
5, 8, 9
6, 11, 12
7, 13, 14
As you may have noticed, this is hierarchical data using the nested set model http://tr.im/EO3G. Tree pretty-printed:
1
2
3
4
5
6
7
I want to select all sub projects under project 1 and 4. I can do this with:
SELECT p.id
FROM projects AS p, projects AS ps
WHERE (ps.id = 1 OR ps.id = 4)
AND p.lft BETWEEN ps.lft AND ps.rgt
However, this is very slow with a large table, when running EXPLAIN (Query) i get:
+----+-------------+-------+-------+------------------------+---------+---------+------+------+-------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+------------------------+---------+---------+------+------+-------------------------------------------------+
| 1 | SIMPLE | ps | range | PRIMARY,lft,rgt,lftRgt | PRIMARY | 4 | NULL | 2 | Using where |
| 1 | SIMPLE | p | ALL | lft,lftRgt | NULL | NULL | NULL | 7040 | Range checked for each record (index map: 0x12) |
+----+-------------+-------+-------+------------------------+---------+---------+------+------+-------------------------------------------------+
(The project table has indexes on lft, rgt, and lft-rgt. As you can see, mysql does not use any index, and loops through the 7040 records)
I have found that if I only select for one of the super project, mysql manages to use the indexes:
SELECT p.id
FROM projects AS p, projects AS ps
WHERE ps.id = 1
AND p.lft BETWEEN ps.lft AND ps.rgt
EXPLAINs to:
+----+-------------+-------+-------+------------------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+------------------------+---------+---------+-------+------+-------------+
| 1 | SIMPLE | ps | const | PRIMARY,lft,rgt,lftRgt | PRIMARY | 4 | const | 1 | |
| 1 | SIMPLE | p | range | lft,lftRgt | lft | 4 | NULL | 7 | Using where |
+----+-------------+-------+-------+------------------------+---------+---------+-------+------+-------------+
FINALLY, my question: I there any way i can SELECT rows matching multiple ranges, and still benefit from indexes?