共计 1034 个字符,预计需要花费 3 分钟才能阅读完成。
mysql 版本号是 5.7.28,表 A 有 390W 条记录,应用 InnoDB 引擎,其中 varchar 类型字段 mac 已建设索引,索引办法为 B -tree。B 表仅有 5000+ 条记录。
有一条 SQL 指令是这样写的:SELECT * FROM A WHERE mac IN("aa:aa:aa:aa:aa:aa","bb:bb:bb:bb:bb:b",... 此外省略 900+ 条)
通过查问进去的后果耗时 294.428s。没错,将近 5 分钟。
应用 EXPLAIN 剖析下:
拜访类型 type 是 range,且已命中索引,rows 行也只有 587776,可为什么查问耗时要这么久?
mac 的索引办法应用了 B -tree,那比照下它与 HASH 的区别,简略地总结下:B-tree 索引能够用于进行 =,>,>=,<,<= 和 between 的计算,而 HASH 只能进行等值运算,不能进行范畴查找。那 IN 是等值运算,两种索引办法都实用。即然这样,把 mac 的索引办法批改为 HASH,同样的查问耗时为。
既然调整索引办法并不能显著地晋升语句的查问性能,那只能从语句自身中进行解决。其实明眼人刚开始一看就晓得,SELECT * 是很耗性能的,那咱们只查业务上须要的字段,语句调整为:SELECT id,mileage FROM A WHERE mac IN("aa:aa:aa:aa:aa:aa","bb:bb:bb:bb:bb:b",... 此外省略 900+ 条)
耗时并没有显著的晋升。
居然 IN 的形式这么难优化,是不是能够放弃应用 LEFT JOIN 呢?语句调整为:SELECT a.id,a.mileage FROM A a LEFT JOIN B b ON b.mac = a.mac WHERE b.create_time >= '2020-01-01'
耗时超过 5 分钟,放弃。
咱们晓得,在条件量少的状况,EXISTS 和 IN 的成果没有显示的差异。但条件多的时候,IN 要比 EXISTS 的效率也高,来试下 EXISTS:SELECT id,mileage FROM A a WHERE EXISTS(SELECT mac FROM B WHERE create_time >= '2020-01-01' AND mac = a.mac)
耗时也是超过 5 分钟,IN 的效率的确要比 EXISTS 高,放弃。
所以最初的论断是,如果 IN 后接大数据量的 String,要谨慎。
在我的项目中我把 mac 作为惟一标识建设与 id 的对应表,在 A 表应用 mac_id 代替 mac,查问的时候应用 IN(1,2,3…)。效率会进步一些。以后应用 NoSQL 也是一种形式。