sql - 禁止 MySQL 对查询使用全表扫描

标签 sql mysql query-optimization

有什么办法可以禁止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 就好了。

更新。我不能接受我自己的回答,因为它并没有真正回答问题(尽管 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 使用主键。

关于sql - 禁止 MySQL 对查询使用全表扫描,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1617317/

相关文章:

sql - 找到数值序列中最大的间隙

sql - 在桥/数据相交表中查找 "missing"记录

mysql - 如何在VB中打印Datagridview有表

php - 在 PHP 中格式化 MySQL 日期时间

sql - 查询性能改进——排序过滤器

facebook-graph-api - 查询优化和 API 限制

mysql - SQL - Where...In 子句中的选择联合

mysql - MySQL 中何时使用单引号、双引号和反引号

mysql - 请优化多连接查询

SQL Server 在 sql 变量中存储多个值