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也是一种形式。