五个提升 SQL 语句性能的小窍门,进一步提升查询性能
在进行数据库操作时,优化 SQL 语句是提升性能和效率的关键步骤之一。无论是处理大规模数据还是简单的查询,优化 SQL 语句都可以明显改善系统的响应时间和资源利用率。
本文介绍五个实用的优化 SQL 的技巧,帮助读者更好地利用索引、避免性能瓶颈,并提高数据库的整体性能。
1 内连接说明
当涉及到多个表的连接查询时,通常使用 join 关键字。
最常用的连接方式是左连接和内连接。
left join:找到两个表的交集,并包含左表中剩余的数据。
inner join:找到两个表的交集数据。
以下是使用 inner join 的示例:
如果两个表使用 inner join 关联,MySQL 会自动选择两个表中的小表驱动大表,因此在性能上不会出现太多问题。
以下是使用 left join 的示例:
如果两个表使用 left join 关联,MySQL 默认使用左连接关键字驱动右侧的表。如果左表中存在大量数据,则可能会出现性能问题。
需要注意的是,在使用 left join 查询时,应该将小表放在左侧,将大表放在右侧。如果可以使用 inner join,应尽量避免使用 left join。
2 限制索引的数量
众所周知,索引可以大幅提高 SQL 查询的性能,但索引的数量并不是越多越好。
因为当向表中添加新数据时,同时需要为其创建索引,而索引需要额外的存储空间和一定的性能消耗。
单个表中的索引数量应尽量控制在 5 个以内,单个索引中的字段数量也不应超过 5 个。
MySQL 使用的 B+树结构来保存索引,B+树索引在插入、更新和删除操作时需要进行更新。如果索引过多,将消耗大量的额外性能。
那么,如果表中的索引过多,超过了 5 个怎么办呢?
这个问题需要辩证地看待。如果你的系统并发性较低,表中的数据量也不是很大,实际上可以使用超过 5 个的索引,只要不过度即可。
但对于一些高并发的系统,务必遵守单个表上不超过 5 个索引的限制。
那么,高并发系统如何优化索引的数量呢?
如果可以建立联合索引,就不要建立单个索引,可以删除一些无用的单个索引。
将一些查询功能迁移到其他类型的数据库中,比如 Elastic Seach、HBase 等,只需在业务表中建立少量的关键索引即可。
3 选择适当的字段类型
char 表示固定长度的字符串类型,该类型的字段存储空间是固定的,会浪费存储空间。
varchar 表示可变长度的字符串类型,该类型的字段存储空间会根据实际数据的长度进行调整,不会浪费存储空间。
如果是固定长度的字段,比如用户的手机号码,一般是 11 位,可以定义为长度为 11 字节的 char 类型。
但如果是企业名称字段,如果定义为 char 类型,会存在问题。
如果长度定义得过长,例如定义为 200 字节,而实际企业名称只有 50 字节,将浪费 150 字节的存储空间。
如果长度定义得过短,例如定义为 50 字节,而实际企业名称有 100 字节,将无法存储,并抛出异常。
因此,建议将企业名称改为 varchar 类型。可变长度字段的存储空间较小,可以节省存储空间,对于查询来说,在相对较小的字段中搜索效率显然更高。
选择字段类型时,应遵循以下原则:
如果可以使用数字类型,就不要使用字符串,因为数字类型的存储空间更小,查询效率更高。
尽量使用小型类型,例如使用 bit 类型存储布尔值,tinyint 类型存储枚举值等。
对于固定长度的字段,可以使用 char 类型。
对于可变长度的字段,可以使用 varchar 类型。
对于金额字段,使用 decimal 类型,避免精度丢失的问题。
4 提高 group by 的效率
在许多业务场景中,需要使用 group by 关键字。它的主要功能是进行去重和分组。
通常,与 having 一起使用,表示按照某些条件进行分组,然后再过滤数据。
错误示例
这种写法性能较差。它首先根据用户 ID 对所有订单进行分组,然后筛选出用户 ID 大于或等于 200 的用户。
分组是一个相对耗时的操作,为什么不在分组之前缩小数据范围呢?
正确示例
使用 where 条件在分组之前过滤掉冗余数据,这样在分组时效率会更高。
实际上,这是一个思路,不仅仅适用于 group by 的优化。在 SQL 语句执行一些耗时操作之前,应尽量缩小数据范围,这样可以提高整体 SQL 的性能。
5 索引优化
在 SQL 优化中,索引优化是非常重要的内容。
在许多情况下,使用索引和不使用索引时,SQL 语句的执行效率会有很大差异。因此,索引优化是 SQL 优化的首选。
索引优化的第一步是检查 SQL 语句是否已经使用了索引。
那么,如何检查 SQL 是否使用了索引呢?
可以使用 explain 命令查看 MySQL 的执行计划。
以下是索引失效的一些常见原因:
不满足最左前缀原则。
范围索引列没有放在最后。
使用了 select *。
对索引列进行了计算。
对索引列使用了函数。
字符串类型没有加引号。
使用了 like %。
错误地使用了 is null。
错误地使用了 or。
如果不是由于上述原因,就需要进一步调查其他原因。
此外,您是否曾经遇到过这样的情况:明明是相同的 SQL,只是输入参数不同。有时候索引 a 生效,有时候索引 b 生效?
有时候 MySQL 会选择错误的索引。
如果有必要,可以使用 force index 来强制查询 SQL 使用特定的索引。
版权声明: 本文为 InfoQ 作者【高端章鱼哥】的原创文章。
原文链接:【http://xie.infoq.cn/article/9ec295ec816405a22161de643】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论