Mysql 选择不使用索引的查询变量

Mysql 选择不使用索引的查询变量,mysql,indexing,hierarchical-data,adjacency-list,query-variables,Mysql,Indexing,Hierarchical Data,Adjacency List,Query Variables,我(出于兴趣)在一个简单的邻接列表中检索节点树,并使用局部变量进行递归查询 到目前为止,我的解决方案很有趣,但我想知道(这是我唯一的问题)为什么MySQL拒绝使用任何索引来优化这个查询。MySQL难道不能使用索引查找最近的子级吗 我很好奇为什么MySQL没有。即使我使用强制索引执行计划也不会改变 这是到目前为止的查询,5是父节点的ID: SELECT @last_id := id AS id, parent_id, name, @depth := IF(parent_id =

我(出于兴趣)在一个简单的邻接列表中检索节点树,并使用局部变量进行递归查询

到目前为止,我的解决方案很有趣,但我想知道(这是我唯一的问题)为什么MySQL拒绝使用任何
索引来优化这个查询。MySQL难道不能使用
索引查找最近的子级吗

我很好奇为什么MySQL没有。即使我使用
强制索引
执行计划也不会改变

这是到目前为止的查询,
5
是父节点的ID:

SELECT 
  @last_id := id AS id,
  parent_id,
  name,
  @depth := IF(parent_id = 5, 1, @depth + 1) AS depth
FROM 
  tree FORCE INDEX (index_parent_id, PRIMARY, index_both),
  (SELECT @last_id := 5, @depth := -1) vars
WHERE id = 5 OR parent_id = @last_id OR parent_id = 5

请注意,原因不可能是小数据集,因为当我指定
FORCE INDEX(id)
FORCE INDEX(parent\u id)
FORCE INDEX(id,parent\u id)
时,行为不会改变

文件说:

您还可以使用强制索引,其作用类似于使用索引(INDEX_list),但另外,表扫描被认为是非常昂贵的。换句话说,只有在无法使用给定索引之一查找表中的行时,才使用表扫描

一定有什么东西使得查询无法使用索引,但我不明白它是什么


免责声明:我知道在SQL中存储和检索分层数据有不同的方法。我知道嵌套集模型。我不是在寻找替代的实现。我不是在找嵌套集

我也知道这个查询本身是错误的,会产生错误的结果


我只是想(详细地)理解为什么MySQL在这种情况下不使用
索引。原因在于WHERE子句中使用了条件

为了举例说明,请再次尝试运行查询,这次仅使用
id=5
条件,并获取(解释输出):

MySQL不太擅长在同一个查询中处理多个索引。情况稍有好转,;人们更可能看到优化而不是优化

随着版本的发展,情况正在改善,但我已经测试了您查询的版本
5.5
,这是当前最新的生产版本,结果如您所述

要解释为什么这很困难,请考虑:两个不同的索引将为查询的两个不同条件提供答案。一个为
id=5
,另一个为
parent\u id=@last\u id或parent\u id=5
(顺便说一句,后者内部的没有问题,因为这两个术语都是从同一个索引中处理的)

没有一个索引可以同时解决这两个问题,因此将忽略
FORCE index
指令。请参阅,
FORCE INDEX
说MySQL必须在表扫描上使用索引。这并不意味着它必须在表扫描中使用多个索引

所以MySQL遵循这里文档的规则。但这为什么这么复杂?因为要回答使用两个索引的问题,MySQL必须从这两个索引中收集结果,在管理第二个索引时将一个索引存储在某个临时缓冲区中。然后,is必须遍历该缓冲区以过滤出相同的行(可能某些行适合所有条件)。然后扫描缓冲区以返回结果

但是等等,缓冲区本身并没有索引。筛选重复项不是一项显而易见的任务。所以MySQL更喜欢在原始表上工作并在那里进行扫描,避免所有的混乱


这当然是可以解决的。Oracle的工程师可能会改进这一点(最近他们一直在努力改进查询执行计划),但我不知道这是否在TODO任务中,或者它是否具有高优先级。

有时一个表的记录太少,使用索引比读取整个表的开销更大。@randy现在有一个合理的论点。。。
+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+
| id | select_type | table      | type   | possible_keys      | key     | key_len | ref   | rows | Extra          |
+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+
|  1 | PRIMARY     | <derived2> | system | NULL               | NULL    | NULL    | NULL  |    1 |                |
|  1 | PRIMARY     | tree       | const  | PRIMARY,index_both | PRIMARY | 4       | const |    1 |                |
|  2 | DERIVED     | NULL       | NULL   | NULL               | NULL    | NULL    | NULL  | NULL | No tables used |
+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+
+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+
| id | select_type | table      | type   | possible_keys   | key  | key_len | ref  | rows | Extra          |
+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+
|  1 | PRIMARY     | <derived2> | system | NULL            | NULL | NULL    | NULL |    1 |                |
|  1 | PRIMARY     | tree       | ALL    | index_parent_id | NULL | NULL    | NULL |   10 | Using where    |
|  2 | DERIVED     | NULL       | NULL   | NULL            | NULL | NULL    | NULL | NULL | No tables used |
+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+