写这个文章的起因是,因为面试的时候又面试官问我,a left join b和b right join a,有什么区别,我说没什么区别,查询结果一样,性能也一样,那个面试官便说,小表和大表的前后顺序对性能是有影响的,他说sql语句从左往右执行,如果左边是大表,会先扫描左边的表的数据,然后再扫描右边表的数据,真是误人子弟啊!下面用实践来打他脸!
我会有SqlServer和MySql分别做实践,因为这两个数据库在Sql执行解析的机制还是有很大不同的。
SqlServer:
tEBay_Trade=》数据量500W tPublic_Shop=>数据量30
-----如果where条件命中索引 且只有一个索引 --关于join 不管是大表在前还是小表在前,查询顺序总是以where索引所在表为第一扫描的表
select * from tPublic_Shop s join tEBay_Trade t on s.id=t.ShopID where s.Id>10
select * from tPublic_Shop s join tEBay_Trade t on s.id=t.ShopID where t.CreateDate>'2021-01-01'
--对于left join和right join 总是会以where条件索引所在的表为第一扫描表
select * from tEBay_Trade t left join tPublic_Shop s on s.id=t.ShopID where t.CreateDate>'2021-01-01'
select * from tPublic_Shop s left join tEBay_Trade t on s.id=t.ShopID where t.Id>10
select * from tPublic_Shop s right join tEBay_Trade t on s.id=t.ShopID where t.CreateDate>'2021-01-01'
-----如果where条件命中索引 且有多个索引 --关于join 不管大表在前还是小表在后,如果有多个where条件命中索引,那么会以索引对应的最大的那个表为第一扫描表
select * from tPublic_Shop s join tEBay_Trade t on s.id=t.ShopID where s.Id>10 and t.CreateDate>'2021-01-01'
select * from tEBay_Trade t join tPublic_Shop s on s.id=t.ShopID where t.CreateDate>'2021-01-01' and s.Id>10
-----如果没有索引或where条件未命中索引 --join 如果没有索引或where条件未命中索引,系统会自动选择小表作为第一扫描表
select * from tPublic_Shop s join tEBay_Trade t on s.id=t.ShopID
select * from tEBay_Trade t join tPublic_Shop s on s.id=t.ShopID
--left join和right join 如果没有索引或where条件未命中索引,系统会自动选择小表作为第一扫描表
select * from tEBay_Trade t left join tPublic_Shop s on s.id=t.ShopID
select * from tPublic_Shop s left join tEBay_Trade t on s.id=t.ShopID
select * from tPublic_Shop s right join tEBay_Trade t on s.id=t.ShopID
MySql这货就很不一样了,正规的跟野生的差别很明显:
tuser数据量:33954 torder数据量:4612
#关于join 不管索引是不是加在主表上,总是先扫描最小的表
select * from tuser u join torder t on u.id=t.uid where u.id>500
select * from tuser u join torder t on u.id=t.uid where t.createtime>='2021-07-01'
select * from torder t join tuser u on u.id=t.uid where u.id>500
#不管是left join还是right join,如果没有条件命中索引,都是以主表为第一扫描的表
select * from torder t left join tuser u on u.id=t.uid
select * from tuser u right join torder t on u.id=t.uid
select * from tuser u left join torder t on u.id=t.uid
#不管是left join还是right left,如果where条件命中索引,会以这个索引对应的表为第一扫描的表
select * from torder t right join tuser u on u.id=t.uid where t.createtime>='2021-07-01'
select * from torder t right join tuser u on u.id=t.uid where u.id>500
select * from tuser u left join torder t on u.id=t.uid where t.createtime>='2021-07-01'
select * from tuser u left join torder t on u.id=t.uid where u.id>500
总结:
关于SqlServer:
1、对于join,left join,right join,不管是大表在前还是小表在前,如果where条件命中索引,总会以where条件索引所在表为第一扫描的表
2、对于join,left join,right join,不管是大表在前还是小表在前,如果where条件命中索引,而且是多个索引,那么会以索引对应的最大的那个表为扫描的第一个表
3、对于join,left join,right join,不管是大表在前还是小表在前,如果where条件没有命中索引,系统会自动选择小表作为第一扫描表
关于MySql:
1、对于join,不管是大表在前还是小表在前,如果where条件命中索引,总是先扫描小表,而不是索引所在的表
2、对于left join和right join,不管是大表在前还是小表在前,如果where条件命中索引,会以索引对应的这个表为第一扫描的表
3、对于left join和right join,不管是大表在前还是小表在前,如果没有条件命中索引,都是以主表为第一扫描的表
所以:表的执行顺序是不以人的主管意志为转移的,如果自己不清楚,请不要随便讲出来。实践是检验真理的唯一标准