【问题标题】:Why the EXTRA is NULL in Mysql EXPLAIN? Why >= is Using index condition?为什么在 Mysql EXPLAIN 中 EXTRA 为 NULL?为什么 >= 是使用索引条件?
【发布时间】:2020-10-08 19:16:06
【问题描述】:
mysql> CREATE TABLE `t` (
     `id` int(11) NOT NULL,
     `a` int(11) DEFAULT NULL,
     `b` int(11) DEFAULT NULL,
     PRIMARY KEY (`id`),
     KEY `a` (`a`),
     KEY `b` (`b`)
   ) ENGINE=InnoDB

有一个名为 t 的表,它有两个名为 a 和 b 的索引。 插入t 100000行数据

mysql> create procedure idata()
  begin
   declare i int;
     set i=1;
     while(i<=100000)do
       insert into t values(i, i, i);
       set i=i+1;
     end while;
   end;
Query OK, 0 rows affected (0.01 sec)

mysql> delimiter ;
mysql> call idata();

我做了一些实验,一些如下

现在,我想知道;

(1)为什么explain select * from t where a &gt;= 90000; extra 是Using index condition?它有索引键,但它没有索引过滤器和表过滤器,那为什么是Using index condition

(2)为什么explain select * from t where a = 90000; extra 是NULL?是需要访问表的,如果第一种情况是Using index condition,为什么第二种不能是Using index condition

(3)为什么explain select a from t where a &gt;= 90000; extra 是Using where; Using index?我知道它使用封面索引,所以额外有Using index;但为什么额外有Using where?这意味着服务器需要过滤数据?但是存储引擎已经返回正确,为什么服务器需要filer?

【问题讨论】:

标签: mysql innodb explain


【解决方案1】:

您的第一个和最后一个查询使用 WHERE 与其他行进行隐式比较,在这种情况下,它会使用索引并将其显示在额外字段(类型范围)中。

当你创建一个结果为 0-1 的条件时,它可以直接访问它们(O(1) 查找)。没有比较或排序发生,只取一行,返回它。

【讨论】:

  • so...第一个和最后一个查询的类型都是范围,但是在我看来,存储引擎已经通过索引过滤了正确的数据,那么为什么服务器需要隐式比较?
  • @Journey 因为使用&gt; 您将行与数字90000 进行比较
  • @Journey - “范围”指的是 BTree 中的一堆连续行(索引或数据)。在您的情况下,它是“以 90000 开始并一直到结束的项目”。
  • @DanielW。所以,在您看来,您选择的数据已经从二级索引中获取(在第三种情况下),但是由于 where 子句中的&gt;,服务器必须进行不必要的比较?
  • @RickJames 我真的知道“范围”的含义,但我在第三种情况下感到困惑,为什么额外的有 Using Where,在我看来,“Using Where”意味着服务器有一个过滤器根据“表格过滤器”,但是“a”列已经返回到服务器,为什么服务器需要进行不必要的比较...我认为没有意义
【解决方案2】:

首先,术语...

“使用索引”意味着(在这种情况下)INDEX(a) 包含所有需要的列。即“索引覆盖”。

“使用索引条件”是完全不同的。在内部,它被称为 ICP(索引条件下推)。这指的是“处理程序”是否检查表达式或“条件”(a >= 90000)是否移交给引擎(InnoDB)来完成工作。

至于“在哪里使用”;这对我来说仍然是个谜,即使在使用 MySQL 20 年并查看了数千个解释之后。我忽略它。

在所有 3 个案例中,都使用了 INDEX(a)。这主要由“key”(“a”——键的名称,而不是列)、“key_len”(“5”:4 字节 INT 加上 1 表示 NULLable)表示,其次是“类型”(不是说“全部”)。

进一步

  • 如果你把90000改成70000,你可能会发现它会切换到表扫描。为什么要在索引的 BTree 和数据的 BTree 之间来回跳动(通过PRIMARY KEY)。优化器将假定简单地扫描所有表会更快,忽略WHERE 子句失败的行。

  • EXPLAIN FORMAT=JSON SELECT -- 为您提供更多信息。 (对于这个简单的查询,可能没有更多信息。)一个有用的惊喜是它会显示 多少 对“文件排序”的单一提及真正指代。 (实现这一点的一种可能简单的方法是GROUP BY x ORDER BY y;即按不同列分组和排序。)

  • 解释很少有像你的“10001”这样干净的数字。通常,“行”列是一个近似值,有时是一个可怕的近似值。

  • 慢日志记录“检查的行数”;它可能会说 10001(或者可能只有 10000)和 1 用于您的测试。对于表扫描,它将是完整的 100K。

  • 获取“检查行”的另一种方法是通过“处理程序”STATUS 值。见http://mysql.rjweb.org/doc.php/index_cookbook_mysql#handler_counts

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-29
    • 2016-06-24
    • 2014-03-18
    • 2010-11-18
    • 1970-01-01
    相关资源
    最近更新 更多