都说in查询比较慢,要改成子查询模式,ChatGPT大模型告诉了我,SQL中替换In查询的10种方法,太赞了,按照这个说的集中方法,验证一下。因为实际项目中确实存在in很多的情况。
查询执行的先后顺序对优化有必要,因此下面的逻辑需要了解。
in 先执行子查询,使用于内小,外大
exist 先执行外层表驱动表,适用于外小,内大
in适合 外层大, 内层小, 先执行内层子查询,过滤出来一小部分数据,再用来查外层
exist适用于外层小,内层大,先执行外层驱动表查询,出来一部分数据,再查内层表
下面的in里面的值不是固定的,
SELECT id, as_id, aa_type, CODE, NAME, mnemonic, remark, STATUS, create_user, create_time, update_user, update_time FROM acc_assisting_accounting WHERE ( STATUS IN ('01', '02') AND as_id = 1 AND id IN ( 374663, 510330, 510333, 374826, 194, 230, 111, 233, 357, 564001, 96, 564000, 10, 11, 12, 13, 563675, 15, 16, 441211, 362, 363, 121, 364, 243, 365, 410181, 526376, 366, 367, 425305, 400, 445538, 368, 402, 369, 127, 403, 8, 9, 510315, 24, 25, 374564, 367070, 370, 374725, 371, 250, 372, 251, 373, 131, 374, 386148, 375, 376, 134, 377, 139, 564023, 564144, 564145, 563331, 561273, 564143, 32, 564148, 564146, 564147, 519437, 564029, 374792, 380, 374835, 381, 260, 382, 261, 141, 384, 385, 419973, 386, 388, 524699, 357442, 149, 420959, 305, 510336, 564150, 564155, 564156, 494009, 456443, 564154, 564157, 371993, 564158, 390, 393, 154, 397, 276, 399, 313, 159, 564162, 564163, 564161, 52, 564167, 564164, 374974, 374854, 564169, 563998, 374210, 160, 162, 466216, 163, 164, 165, 320, 321, 288, 169, 364386, 329, 60, 209, 62, 524790, 514113, 365133, 294, 173, 295, 333698, 296, 176, 331, 332, 214, 215, 344905, 337, 338, 381698, 363223, 394580, 374091, 77, 374634, 510387, 183, 340, 341, 342, 343, 102, 345, 346, 380752 )) ORDER BY CODE ASC
mysql解析器,查看一下扫描rows很少啊
select_type
中SIMPLE
表示简单查询,不包含子查询或UNION
1 find_in_set过滤的模式
基本上全表扫描了
2 exists替换in操作符
从实际效果验证,依旧不好。还不如in,固然chatgpt说的专家,也就是砖家。不要认为exist
就一定性能好。
3 with方式
with as
方式mysql5.7及以下
版本不支持,而我们的生产环境就是mysql5.7,因此这条路是走不通的。
不过我还是想知道,这个效果怎么样,于是在本地的mariadb上运行,效果如下,嗯,貌似有进步。不过也让我研究一下explain的结果是啥意思。
虽然上面type出现了ALL
,但那是临时表,也就是in里面的内容,所以没有影响。主表是eq_ref
因为走了逐渐索引
select_type
中MATERIALIZED
说明采用的是物化视图,因为物化视图是预计算和存储的查询结果,用于提高查询性能,也就是说with as
会创建物化视图,有助于性能优化
PRIMARY
显示最外层的select语句是我的主表aaa
虽然mysql 5.7
不支持with
写法,可以通过下面的方式来实现
SELECT aaa.*
from acc_assisting_accounting aaa
inner join (
select 1 as id union allselect 2 as id union allselect 3 as id union allselect 4 as id union allselect 23 as id union allselect 24 as id
) t on t.id = aaa.id
where as_id=112514
DERIVED
表示派生表,通过子查询中派生的临时表
4 虚拟表
将in的内容,创建一个临时表,按照别人的示例,我为什么执行不通过呢?语句貌似没有错误.
查看mysql select 临时表, 应该是要先创建一张temp
的临时表。
但是看了mysql临时表 表变量_SQL 使用 VALUES 生成带数据的临时表实例代码详解,好像有不对