[英]Prohibit MySQL from using full table scan on a query
当使用索引找不到结果时,有什么方法可以禁止MySQL执行全表扫描?
例如这个查询:
SELECT *
FROM a
WHERE (X BETWEEN a.B AND a.C)
ORDER BY a.B DESC
LIMIT 1;
仅在X满足条件且返回至少1行时才有效,但如果表中的任何数据无法满足条件,则将执行完全扫描,这可能非常昂贵。
我不想优化这个特定的查询,它只是一个例子。
使用范围内或范围外的X来解析此查询:
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE a range long_ip long_ip 8 \N 116183 100.00 Using where
STATUS VARIABLE显示更好的信息。 对于超出范围的X:
Handler_read_prev 84181
Key_read_requests 11047
在范围内:
Handler_read_key 1
Key_read_requests 12
如果只有一种方法可以阻止Handler_read_prev过去1增长。
UPDATE。 我不能接受我自己的答案,因为它并没有真正回答这个问题(HANDLER是一个很棒的功能)。 在我看来,没有通用的方法来阻止MySQL进行全面扫描。 虽然像key ='X'这样的简单条件将被视为“不可能的地方”,但像BETWEEN这样的更复杂的事情则不会。
您可以编写一个“完全覆盖”的子查询,该子查询仅使用索引中可用的数据。 根据返回的主键,您可以在主表中查找行。
以下查询完全由(id),(B,id)和(C,id)上的索引覆盖:
select *
from a
where id in (
select id
from a
where x <= C
and id in (
select id
from a
where B <= X
)
)
limit 1
每个SELECT使用一个索引:最内层的索引(B,id); 中间的SELECT使用索引(C,id),外部SELECT使用主键。
以下是我最终提出的建议:
HANDLER a OPEN;
HANDLER a READ BC <= (X);
HANDLER a CLOSE;
BC是密钥(B,C)的名称。 如果我们通过B DESC对表进行排序,则保证结果等于
SELECT *
FROM a
WHERE (X BETWEEN a.B AND a.C)
ORDER BY a.B DESC
LIMIT 1;
现在,如果X不在表a的范围内,我们只需要检查aC是否大于X,如果不是,那么X绝对超出范围,我们不需要再看了。
虽然这不是很优雅,但您必须在每次插入或更新时使用该表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.