聊聊sql优化的15个小技巧,太赞了( 三 )

子查询语句可以通过in关键字实现,一个查询语句的条件落在另一个select语句的查询结果中 。程序先运行在嵌套在最内层的语句,再运行外层的语句 。
子查询语句的优点是简单,结构化,如果涉及的表数量不多的话 。
但缺点是mysql执行子查询时,需要创建临时表,查询完毕后,需要再删除这些临时表,有一些额外的性能消耗 。
这时可以改成连接查询 。具体例子如下:
select o.* from order oinner join user u on o.user_id = u.idwhere u.status=110 join的表不宜过多根据阿里巴巴开发者手册的规定,join表的数量不应该超过3个 。
反例:
select a.name,b.name.c.name,d.namefrom a inner join b on a.id = b.a_idinner join c on c.b_id = b.idinner join d on d.c_id = c.idinner join e on e.d_id = d.idinner join f on f.e_id = e.idinner join g on g.f_id = f.id如果join太多,mysql在选择索引的时候会非常复杂,很容易选错索引 。
并且如果没有命中中,nested loop join 就是分别从两个表读一行数据进行两两对比,复杂度是 n^2 。
所以我们应该尽量控制join表的数量 。
正例:
select a.name,b.name.c.name,a.d_name from a inner join b on a.id = b.a_idinner join c on c.b_id = b.id如果实现业务场景中需要查询出另外几张表中的数据,可以在a、b、c表中冗余专门的字段,比如:在表a中冗余d_name字段,保存需要查询出的数据 。
不过我之前也见过有些ERP系统,并发量不大,但业务比较复杂,需要join十几张表才能查询出数据 。
所以join表的数量要根据系统的实际情况决定,不能一概而论,尽量越少越好 。
11 join时要注意我们在涉及到多张表联合查询的时候,一般会使用join关键字 。
而join使用最多的是left join和inner join 。

  • left join:求两个表的交集外加左表剩下的数据 。
  • inner join:求两个表交集的数据 。
使用inner join的示例如下:
select o.id,o.code,u.name from order o inner join user u on o.user_id = u.idwhere u.status=1;如果两张表使用inner join关联,mysql会自动选择两张表中的小表,去驱动大表,所以性能上不会有太大的问题 。
使用left join的示例如下:
select o.id,o.code,u.name from order o left join user u on o.user_id = u.idwhere u.status=1;如果两张表使用left join关联,mysql会默认用left join关键字左边的表,去驱动它右边的表 。如果左边的表数据很多时,就会出现性能问题 。
要特别注意的是在用left join关联查询时,左边要用小表,右边可以用大表 。如果能用inner join的地方,尽量少用left join 。
12 控制索引的数量众所周知,索引能够显著的提升查询sql的性能,但索引数量并非越多越好 。
因为表中新增数据时,需要同时为它创建索引,而索引是需要额外的存储空间的,而且还会有一定的性能消耗 。
阿里巴巴的开发者手册中规定,单表的索引数量应该尽量控制在5个以内,并且单个索引中的字段数不超过5个 。
mysql使用的B+树的结构来保存索引的,在insert、update和delete操作时,需要更新B+树索引 。如果索引过多,会消耗很多额外的性能 。
那么,问题来了,如果表中的索引太多,超过了5个该怎么办?
这个问题要辩证的看,如果你的系统并发量不高,表中的数据量也不多,其实超过5个也可以,只要不要超过太多就行 。
但对于一些高并发的系统,请务必遵守单表索引数量不要超过5的限制 。
那么,高并发系统如何优化索引数量?
能够建联合索引,就别建单个索引,可以删除无用的单个索引 。
将部分查询功能迁移到其他类型的数据库中,比如:Elastic Seach、HBase等,在业务表中只需要建几个关键索引即可 。
13 选择合理的字段类型char表示固定字符串类型,该类型的字段存储空间的固定的,会浪费存储空间 。
alter table order add column code char(20) NOT NULL;varchar表示变长字符串类型,该类型的字段存储空间会根据实际数据的长度调整,不会浪费存储空间 。
alter table order add column code varchar(20) NOT NULL;如果是长度固定的字段,比如用户手机号,一般都是11位的,可以定义成char类型,长度是11字节 。
但如果是企业名称字段,假如定义成char类型,就有问题了 。
如果长度定义得太长,比如定义成了200字节,而实际企业长度只有50字节,则会浪费150字节的存储空间 。


推荐阅读