MySQL 全表扫描

Posted

技术标签:

【中文标题】MySQL 全表扫描【英文标题】:MySQL Full table scan 【发布时间】:2015-02-14 10:55:37 【问题描述】:

好的,在以下查询中,DMSNODE 有 144K 行。并且有一个关于 CHANGEDON、ID、PARENT ID 和 3 的 2 个排列的索引

SELECT
    DISTINCT t0.ID AS a1,
    t0.CHANGEDON,
    t1.id AS a2
FROM
    DMSNODE t0
    LEFT OUTER JOIN DMSNODE t1 ON (t1.ID = t0.PARENT_ID)
ORDER BY
    t0.CHANGEDON ASC
LIMIT
     0, 5

这是表定义

CREATE TABLE `dmsnode` (
    `ID` BIGINT(20) NOT NULL,    
    `PARENT_ID` BIGINT(20) DEFAULT NULL,
    `TITLE` VARCHAR(1024) NOT NULL,
    `CHANGEDON` DATETIME NOT NULL,

    PRIMARY KEY (`ID`),
    KEY `DMSNODE_PARENT_ID_FK` (`PARENT_ID`),
    KEY `DMSNODE_CHANGEDON_IDX` (`CHANGEDON`),
    KEY `idx_dmsnode_ID_PARENT_ID_CHANGEDON` (`ID` , `PARENT_ID` , `CHANGEDON`),
    KEY `idx_dmsnode_ID_PARENT_ID` (`ID` , `PARENT_ID`),

    CONSTRAINT `DMSNODE_FOLDER_ID_FK` FOREIGN KEY (`PARENT_ID`)
        REFERENCES `dmsnode` (`ID`),
    )  ENGINE=INNODB DEFAULT CHARSET=UTF8 COMMENT='DMS Node'

并且 EXPLAIN 显示全表扫描

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE      t0      index   ""idx_dmsnode_ID_PARENT_ID_CHANGEDON    25  ""  144982  Using index; Using temporary; Using filesort
1   SIMPLE      t1      eq_ref  PRIMARY,idx_dmsnode_ID_PARENT_ID_CHANGEDON,idx_dmsnode_ID_PARENT_ID PRIMARY 8   tbibms.t0.PARENT_ID 1   Using index

有人可以解释为什么要执行全表扫描以及如何避免它吗?我认为使用 CHANGEDON 上的索引就足以首先选择前 5 个 changedon 行,然后进行左外连接

【问题讨论】:

这可能是 DISTINCT。是否真的需要它,或者您可以将其删除或将其移动到派生表中吗? 【参考方案1】:

您的查询中没有 WHERE 子句,因此数据库引擎必须查看这两个表中的每一行。在这种情况下,全表扫描将导致比使用索引更少的 I/O。

分享和享受。

【讨论】:

我试图简化问题。 where 子句在另一个左连接上,不在使用索引的示例中。实际查询是:从左连接 b 中选择前 5 条记录,其中 a 在 b 上没有任何匹配记录。如果没有全表扫描 Bob,有什么办法可以做到这一点? 请编辑问题并包含完整的查询。 *** 上的许多开发人员都很好,但根据我的水晶球,我们都不是读心者。 :-) 谢谢。

以上是关于MySQL 全表扫描的主要内容,如果未能解决你的问题,请参考以下文章

MySQL视图是不是总是进行全表扫描?

MySQL 全表扫描

MySQL 全表扫描

mysql in 子查询无法使用索引全表扫描 慎用in

mysql in 子查询无法使用索引全表扫描 慎用in

mysql in 子查询无法使用索引全表扫描 慎用in