mysql的in查询的常规优化
记录于2021年2月份,以后的mysql版本可能会有优化处理,但当前in相关的查询仍然存在索引失效等问题。
转载自: 《MySQL中使用IN会不会走索引分析》的结论:IN肯定会走索引,但是当IN的取值范围较大时会导致索引失效,走全表扫描。
By the way:如果使用了 not in,则不走索引。
以下介绍两种常见场景的优化,不详述原理部分。
- 和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; - 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;
- 其它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,如果有必要,就将查询结果放到临时表中,甚至在临时表中进行排序。