mysql的in查询的常规优化

记录于2021年2月份,以后的mysql版本可能会有优化处理,但当前in相关的查询仍然存在索引失效等问题。
转载自: 《MySQL中使用IN会不会走索引分析》的结论:IN肯定会走索引,但是当IN的取值范围较大时会导致索引失效,走全表扫描。
By the way:如果使用了 not in,则不走索引。

以下介绍两种常见场景的优化,不详述原理部分。

  1. 和in相关的子查询优化
    原sql:
    SELECT *
    FROM test_table
    WHERE
    test_id IN (
    SELECT test_id FROM test_table WHERE name > ‘2021-02-19 14:50:06’
    ) ;
    推荐方式:
    SELECT a.*
    FROM test_table a,(SELECT test_id FROM test_table WHERE name > ‘2021-02-19 14:50:06’)b
    WHERE
    a.test_id =b.test_id;
  2. in的取值量较大的情况
    SELECT *
    FROM test_table
    WHERE
    test_id IN (1613717283,1613717284,1613717285,1613717383,
    1613727283,1673717284,1656717285,1623717383,
    1613747283,1683717284,1645717285,1634717383,
    1613757283,1633717284,1634717285,1654717383,
    1613767283,1643717284,…);

推荐方式:使用force index(索引名)强制使用索引
SELECT *
FROM test_table
force index(test_id)
WHERE
test_id IN (1613717283,1613717284,1613717285,1613717383,
1613727283,1673717284,1656717285,1623717383,
1613747283,1683717284,1645717285,1634717383,
1613757283,1633717284,1634717285,1654717383,
1613767283,1643717284,…);

注:根据版本的不同,以及各种云端上对应mysql的优化。in的取值数量对索引使用的影响也不同。在腾讯云上,可能在上万条才会导致in不走索引。因此各位也可以根据自己数据库的实际情况,来做分批的in查询。

注:案例所对应的表结构
CREATE TABLE test_table (
id bigint(20) NOT NULL AUTO_INCREMENT,
name varchar(20),
test_id bigint(20) NOT NULL,
PRIMARY KEY (id),
KEY test_id (test_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  1. 其它mysql操作相关的强制命令:
    1.强制索引 FORCE INDEX
    2.忽略索引 IGNORE INDEX
    3.关闭查询缓冲 SQL_NO_CACHE 实时地查询数据,不管这条SQL语句是否被执行过,服务器都不会在缓冲区中查找,每次都会执行它。
    4.强制查询缓冲 SQL_CACHE
    5.优先操作 HIGH_PRIORITY 使用在select和insert操作中,让MYSQL知道,这个操作优先进行。
    6.滞后操作 LOW_PRIORITY 使用在insert和update操作中,让mysql知道,这个操作滞后
    7.强制连接顺序 STRAIGHT_JOIN 如果你认为按自己的顺序比MySQL推荐的顺序进行连接的效率高的话,就可以通过STRAIGHT_JOIN来确定连接顺序
    8.大结果集缓存SQL_BUFFER_RESULT 当我们查询的结果集中的数据比较多时,可以通过SQL_BUFFER_RESULT.选项强制将结果集放到临时表中,这样就可以很快地释放MySQL的表锁(这样其它的SQL语句就可以对这些记录进行查询了),并且可以长时间地为客户端提供大记录集。
    9.分组使用临时表 SQL_BIG_RESULT和SQL_SMALL_RESULT 一般用于分组或DISTINCT关键字,这个选项通知MySQL,如果有必要,就将查询结果放到临时表中,甚至在临时表中进行排序。