当前位置: 首页 > 科技观察

关于MySQL数据库性能优化方法,看这篇文章就够了

时间:2023-03-13 13:18:39 科技观察

在大量的数据库应用开发项目中,大多数情况下,数据库的运行性能成为整个应用的性能瓶颈。数据库的性能是程序员需要关注的。在设计数据库表结构和操作数据库时(尤其是查询数据时),需要关注数据操作的性能。在本文中,我们以MySQL数据库为例进行讨论。一、数据库优化目标1、减少IO次数。IO永远是数据库最容易出现的瓶颈。这是由数据库的职责决定的。大多数数据库操作占用了IO操作90%以上的时间。减少IO次数是SQL优化的第一要务。当然,这也是最有效的优化方法。2.减少CPU计算除了IO瓶颈,SQL优化需要考虑的就是CPU计算的优化。orderby,groupby,distinct...都是CPU消耗大户(这些操作基本上都是CPU在内存中处理数据比较操作)。当我们的IO优化到了一定阶段后,减少CPU的计算量就成了我们SQL优化的一个重要目标。MySql查询过程二、数据库优化方法1.SQL语句优化定义了优化目标之后,我们需要确定实现目标的方法。对于SQL语句,其实只有一种方法可以达到以上两个优化目标,那就是改变SQL的执行计划,让它尽可能地“少走弯路”,尽量找到我们需要的数据通过各种“捷径”。达到“减少IO次数”和“减少CPU计算”的目的。(1)尽量少加入。MySQL的优点是简单,但在某些方面这也是它的弱点。MySQL优化器效率很高,但由于统计信息量有限,优化器工作过程中出现偏差的可能性较大。对于复杂的多表join,一方面由于其优化器的限制,另一方面在join方面做的不够努力,所以在性能上与关系型数据库的前辈们还有一定的距离,比如神谕。但如果是简单的单表查询,这个差距就会极小,在某些场景下甚至比这些数据库前辈还要好。(2)尽量减少排序(3)排序操作会消耗较多的CPU资源,因此在缓存命中率高、IO能力充足的场景下,减少排序会极大地影响SQL的响应时间。(4)尽量避免select*,尽量用join代替子查询(5)尽量少用“or”关键字。当where子句中有多个条件且“or”并存时,MySQL优化器的效率不是很高。很好的解决了它的执行计划优化问题,再加上MySQL独特的SQL和Storage分层架构,导致性能比较低,很多时候使用unionall或者union(必要的时候)来代替“or”会得到更好的效果。(6)尽量用unionall代替unionunion和unionall。union和unionall的区别在于前者需要将两个(或多个)结果集合并起来,然后进行唯一的过滤操作,会涉及到排序,增加大量的CPU运算。增加资源消耗和延迟。所以当我们可以确认不可能出现重复结果集或者不关心重复结果集时,尽量使用unionall而不是union。(7)避免类型转换(8)能用DISTINCT就不需要GROUPBY(9)尽量不要用SELECTINTO语句?(10)从全局角度优化,而不是片面调整SQL。系统中的所有SQL都要充分考虑,尤其是在通过调整索引来优化SQL执行计划时,千万不能顾此失彼。2、表结构优化MySQL数据库是基于行(Row)存储的数据库,数据库以页(block)的形式进行IO操作。也就是说,如果减少每条记录占用的空间量,就会增加每页可以存储的数据行数,同时每次IO可以访问的行数也会增加。反之,当处理相同行数的数据时,需要访问的页面会减少,也就是IO操作的次数会减少,这会直接提升性能。(1)数据类型选择的原则是:数据行的长度不超过8020字节。如果超过这个长度,这个数据会占用物理页中的两行,会造成存储碎片,降低查询效率;字段的长度应在最大满足可能的需求的前提下,设置的越短越好,这样可以提高查询效率,减少索引时的资源消耗。数字类型:除非绝对必要,否则不要使用DOUBLE。这不仅是存储长度的问题,也是准确性的问题。同样,不建议将DECIMAL用于固定精度的小数。建议乘以固定倍数,然后转化为整数存储,这样可以大大节省存储空间,也不会带来任何额外的维护成本。字符类型:定长字段,推荐使用CHAR类型(char查询速度快,但占用存储空间,可用于用户名、密码等长度变化不大的字段),变长字段尽量使用VARCHAR(varchar查询比较慢但是节省Storage空间,可以用于注释等长度变化较大的字段),并且只设置一个合适的最大长度,而不是非常随意的给一个很大的最大长度限制,因为MySQL会对不同长度范围的存储进行处理。时间类型:尽量使用TIMESTAMP类型,因为它的存储空间只需要DATETIME类型的一半。对于只需要精确到某一天的数据类型,推荐使用DATE类型,因为它的存储空间只需要3个字节,比TIMESTAMP还少。不建议通过INT类型类来存储一个unix时间戳值,因为太不直观,会给维护带来不必要的麻烦,也不会带来任何好处。ENUM&SET:对于status字段,可以尝试使用ENUM来存储,因为可以大大减少存储空间,而且即使需要增加新的类型,只要在末尾添加,结构修改不需要重建表数据。(2)字符编码字符集直接决定了数据在MySQL中的存储编码方式。由于相同的内容使用不同的字符集来表示,不同的字符集所占用的空间,所占用空间的大小也会相差很大,所以通过使用合适的字符集,可以帮助我们尽量减少数据量尽可能减少IO操作的次数。(3)尽量使用NOTNULLNULL类型比较特殊,SQL很难优化。MySQL的NULL类型虽然和Oracle的NULL不同,会进入索引,但是如果是复合索引,那么这个NULL类型字段会极大的影响整个索引的效率。NULL空间虽然可能确实有一定的节省,但是带来了很多其他的优化问题。不但没有节省IO量,反而增加了SQL的IO量。所以尽量保证DEFAULT值不为NULL,这也是一个很好的表结构设计优化习惯。3.数据库架构优化分布式和集群:负载均衡。负载均衡集群由一组相互独立的计算机系统组成,这些计算机系统通过常规网络或专用网络连接,通过路由器相连,各节点相互协作,分担负载,均衡压力。对于客户端来说,整个集群可以看作是一个独立的超高性能服务器。MySQL一般会部署一个读写分离的高可用负载均衡集群,一般只做读负载均衡。读写分离。读写分离简单来说就是将对数据库的读写操作分开,对应不同的数据库服务器,可以有效的降低数据库的压力,也可以降低io的压力。主库提供写操作,从库提供读操作。其实在很多系统中,主要是读操作。当主库进行写操作时,数据必须同步到从库,这样才能有效保证数据库的完整性。数据分割。通过一定的特定条件,将存储在同一个数据库中的数据分散存储在多个数据库中,实现分布式存储,通过路由规则对特定数据库的访问进行路由,使得每次访问面对的不是单个Server,而是N台服务器,从而减轻单机的负载压力。4.其他优化(1)适当使用视图,加快查询速度。对表的子集进行排序并创建视图有时可以加快查询速度(尤其是多次执行的查询)。它有助于避免多次排序操作,并以其他方式简化优化器的工作。视图中的行比主表中的行少,物理顺序是要求的顺序,减少了磁盘I/O,因此可以大大减少查询工作量。(2)算法优化。尽量避免使用游标,因为游标的效率很低。如果游标操作的数据超过10000行,那么就要考虑重写了。在使用基于游标或临时表的方法之前,为您的问题寻找一个基于集合的解决方案,这通常更有效。与临时表一样,游标并非不可用。在小型数据集上使用FAST_FORWARD游标通常优于其他逐行处理方法,尤其是在必须引用多个表才能获取所需数据的情况下。(3)封装存储过程。编译优化后存储在数据库服务器中。运行效率高,可以减少客户端计算机与服务器端的通信量,有利于集中控制,维护方便。