【问题标题】:MYSQL doesn't use index when using NOT INMYSQL 在使用 NOT IN 时不使用索引
【发布时间】:2015-01-28 12:38:49
【问题描述】:

我有一个表,其中有一个列的索引,所以这样的查询:

select * from table where id in (...)

正确使用索引。

但是如果我使用相反的:

select * from table where id not in (...)

则不使用索引。问题是表有超过 10 万行,因此全表扫描非常昂贵。 NOT IN 部分并不小,它可以从表中消除大约 3/4 的行,因此优化器使用这些 id 和索引来消除行并仅对其余行运行全表扫描是有意义的.但根据 EXPLAIN 并没有发生。

有没有办法让MYSQL在第二种情况下使用索引?

【问题讨论】:

    标签: mysql database optimization indexing


    【解决方案1】:

    我刚刚创建了一个带有随机 id 的测试数据库,并在几行中使用了 NOT IN,但它确实使用了索引。 在您的情况下,MySQL 可能认为不使用索引更好,例如由于您的 NOT IN 的分布,可能是数据类型,或者可能只是您的 MySQL 版本。

    但是,可以强制查询使用索引,如page 中所述。

    在您的情况下,您的查询将变为:

    select * from table FORCE INDEX (PRIMARY) where id not in (...)
    

    【讨论】:

    • mysql 使用运行时启发式方法来选择使用哪个索引或是否使用表遍历。相同的 mysql 版本,实际上即使是同一张表,也可以在一个和另一个之间切换。我有一个查询通常需要 1 毫秒才能运行,但每隔几百次调用就需要 4-500 毫秒。我跟踪到它对运行缓慢的版本的不同解释。
    • 正确,MySQL 在每个查询的运行时确定它。正是我的观点:) 但是,如果原始发布者想要专门使用该键,则 FORCE INDEX 应该让 MySQL 使用该索引。
    【解决方案2】:

    id 列表告诉 mysql 跳过哪些,但是要查找表中存在的其他 id,无论如何它必须进行全表扫描,所以它就是这样做的。我不相信 mysql 足够聪明,无法区分主键索引和列索引。

    但是,您可以在查询中自己执行此操作 - 您可以包含一个嵌套查询,该查询提取要返回的 ID,并仅选择这些行。嵌套查询可以使用主键索引。类似的东西

    select * from table join (select id from table where id not in (...)) t using(id)
    

    嵌套查询只查看主键,它会使用索引。选择是通过主键拉出特定的行,它也将使用索引。

    【讨论】:

    • 虽然 ids 列表只告诉哪些要跳过,mysql 仍然可以选择它仍然必须从索引中选择的 ids。所以你的说法并不完全正确。
    • 是的,我在想一个任意的列索引。如果它是 id 列本身,那么它应该能够只遍历主索引,是的。
    猜你喜欢
    • 1970-01-01
    • 2021-09-04
    • 1970-01-01
    • 2014-01-06
    • 2018-12-18
    • 1970-01-01
    • 2013-03-10
    • 1970-01-01
    • 2010-10-09
    相关资源
    最近更新 更多