如何实现高性能的数据处理\数据库性能优化

 

数据库访问优化法则

要正确的优化SQL,我们需要快速定位能性的瓶颈点,也就是说快速找到我们SQL主要的开销在哪里?而大多数情况性能最慢的设备会是瓶颈点,如下载时网络速度可能会是瓶颈点,本地复制文件时硬盘可能会是瓶颈点,为什么这些一般的工作我们能快速确认瓶颈点呢,因为我们对这些慢速设备的性能数据有一些基本的认识,如网络带宽是2Mbps,硬盘是每分钟7200转等等。因此,为了快速找到SQL的性能瓶颈点,我们也需要了解我们计算机系统的硬件基本性能指标,下图展示的当前主流计算机性能指标数据。

如何实现高性能的数据处理\数据库性能优化_第1张图片

 

从图上可以看到基本上每种设备都有两个指标:

延时(响应时间):表示硬件的突发处理能力;

带宽(吞吐量):代表硬件持续处理能力。

 

从上图可以看出,计算机系统硬件性能从高到代依次为:

CPU——Cache(L1-L2-L3)——内存——SSD硬盘——网络——硬盘

由于SSD硬盘还处于快速发展阶段,所以本文的内容不涉及SSD相关应用系统。

根据数据库知识,我们可以列出每种硬件主要的工作内容:

CPU及内存:缓存数据访问、比较、排序、事务检测、SQL解析、函数或逻辑运算;

网络:结果数据传输、SQL请求、远程数据库访问(dblink);

硬盘:数据访问、数据写入、日志记录、大数据量排序、大表连接。

 

数据库访问优化漏斗法则

如何实现高性能的数据处理\数据库性能优化_第2张图片

如何实现高性能的数据处理\数据库性能优化_第3张图片

 

 

由于每一层优化法则都是解决其对应硬件的性能问题,所以带来的性能提升比例也不一样。传统数据库系统设计是也是尽可能对低速设备提供优化方法,因此针对低速设备问题的可优化手段也更多,优化成本也更低。我们任何一个SQL的性能优化都应该按这个规则由上到下来诊断问题并提出解决方案,而不应该首先想到的是增加资源解决问题。

 

以下是每个优化法则层级对应优化效果及成本参考:

 

如何实现高性能的数据处理\数据库性能优化_第4张图片

      

主要总结以下两者优化方式:

       一.硬件优化(有钱出钱)

              能用钱解决的事可以优先用钱解决

       二.应用优化(没钱出力)

              但我们没钱,所以主要关注在这里

一、硬件优化

       .优化服务器硬件

              服务器的硬件性能直接决定着数据库的性能,硬件的性能瓶颈,直接决定数据库的运行速度和效率。

              可从以下几个方面考虑:

              1 、配置较大的内存。足够大的内存,是提高数据库性能的方法之一。

                     内存的IO比硬盘快的多,可以增加系统的缓冲区容量,使数据在内存停留的时间更长,以减少磁盘的IO;

              2 、配置高速磁盘,比如 SSD 。

              3 、使用专业的存储服务器( NAS 、 SAN )

              4 、合理分配磁盘IO,把磁盘IO分散到多个设备上,以减少资源的竞争,提高并行操作能力。

              5 、配置多核处理器, 数据库一般是多线程的,多处理器可以提高同时执行多个线程的能力。

       .优化服务器配置

              合理配置数据库服务器,尽量使应用本身达到一个最合理的使用     

       .分配更多资源

              配置更多的服务器等资源

二、应用优化

       优化方式

       1.设计合理的数据库结构

       2.对数据表建立合适有效的数据库索引

       3.交互优化

       4.编写简洁高效规范的SOL语句

数据库访问优化法则详解:

 

 

1设计合理的数据库结构

              数据库设计需要考虑数据冗余、查询和更新的速度、字段的数据类型是否合理等多方面的内容

              . 分库、分区

                     关系型数据库本身比较容易成为系统瓶颈,单机存储容量、连接数、处理能力都有限。

                     当数据量过大,查询维度较多,面临性能和存储的瓶颈时,考虑分库分区、读写分离等方式。

                     图,表现形式,多业务多库

              .分表

                     将字段很多的表分解成多个表

                     对于字段较多的表,如果有些字段的使用频率很低,可以将这些字段分离出来形成新表。

                     因为当一个表的数据量很大时,会由于使用频率低的字段的存在而变慢。

                     表现形式:如扩展表

              .增加中间表

                     对于需要经常联合查询的表,可以建立中间表以提高查询效率。

                     通过建立中间表,将需要通过联合查询的数据插入到中间表中,然后将原来的联合查询改为对中间表的查询。

              .合理增加冗余字段

                     设计数据表时应尽量遵循范式理论的规约,尽可能的减少冗余字段,让数据库设计看起来精致、优雅。

                     但是,合理的加入冗余字段可以提高查询速度。

                     表的规范化程度越高,表和表之间的关系越多,需要连接查询的情况也就越多,性能也就越差。

              .考虑使用相应缓存服务帮助缓解访问压力

             

              分库分区分表冗余冗余字段的使用,需注意保持同步更新,确保数据一致性。

              方案:

                     1.编写统一更新方法,做好备注说明,相关业务统一调用更新同步数据

                     2.预备数据修复脚本,做好备注说明,以便数据异常时快速修复

             

             

              表结构设计原则

              选择合适的数据类型:如果能够定长尽量定长.

              不要使用无法加索引的类型作为关键字段,比如 text 类型.

              为了避免联表查询,可以适当的数据冗余.

              选择合适的表引擎

              建立合适的数据库索引

2减少数据访问

2.1创建并使用正确的索引

什么字段上建索引?

1、字段出现在查询条件中,并且查询条件可以使用索引;

2、语句执行频率高,一天会有几千次以上;

3.对数据表建立合适有效的数据库索引

              索引:利用字段的某些属性,快速的定位数据(磁盘,柱面,磁道,扇区)

              索引就是类似书的目录,很多时候能很大提高检索数据的效率。

 

              索引创建一般原则 (主要是针对 where 条件进行优化)

                     .频繁的作为查询条件字段应该创建索引

                            select * from emp where empno = 1

                     .唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件

                            select * from emp where sex =‘

                     .更新非常频繁的字段不适合创建索引

                            select * from emp where logincount = 1

                     .不会出现在 WHERE子句中字段不该创建索引

                     .尽量使用短索引,一般对 int char / varcbar dateltime 等类型的字段建立索引

                     .单索引(如主键、外键等)与联合索引(常联合查询的条件)配合使用

                     .对大数据量表建立聚集索引,避免更新操作带来的碎片。

                     .不要过度索引,单表建立的索引不要超过 5 个,否则更新索引将很耗时

 

              索引使用注意事项

                     避免对索引字段进行计算操作

                     避免在索引字段上使用not<>!=

                     避免在索引列上使用IS NULLIS NOT NULL

                     避免在索引列上出现数据类型转换

                     避免在索引字段上使用函数 LEFT() ,SUBSTR()

                     避免建立索引的列中使用空值

 

2.2尽量通过索引访问数据

.这样就可以直接只通过访问索引就能得到数据,一般索引占用的磁盘空间比表小很多,所以这种方式可以大大减少磁盘IO开销,快速定位。

 

.实际数据库中我们不可能把每个SQL请求的字段都建在索引里,所以这种只通过索引访问数据的方法一般只用于核心应用,也就是那种对核心表访问量最高且查询字段数据量很少的查询。

3返回更少的数据

3.1数据分页处理

3.1.1、客户端(应用程序或浏览器)分页

将数据从应用服务器全部下载到本地应用程序或浏览器,在应用程序或浏览器内部通过本地代码进行分页处理

优点:编码简单,减少客户端与应用服务器网络交互次数

缺点:首次交互时间长,占用客户端内存

适应场景:客户端与应用服务器网络延时较大,但要求后续操作流畅

 

3.1.2、数据库SQL分页

 

采用数据库SQL分页需要两次SQL完成

一个SQL计算总数量

一个SQL返回分页后的数据

优点:性能好

缺点:编码复杂,各种数据库语法不同,需要两次SQL交互。

 

3.2只返回需要的字段

通过去除不必要的返回字段可以提高性能,例:

调整前:SELECT * FROM CF_User where UserID=?;

调整后:SELECT UserID,LoginName FROM CF_User where UserID=?;

 

优点:

1、减少数据在网络上传输开销

2、减少服务器数据处理开销

3、减少客户端内存占用

4、字段变更时提前发现问题,减少程序BUG

5、如果访问的所有字段刚好在一个索引里面,则可以使用纯索引访问提高性能。

缺点:增加编码工作量

 

4减少交互次数

 

4.1减少与SQL数据库表交互次数

       Eg:用户实体

       list userList=GetAllUserList();//从数据库中查出所有用户 【给后续业务需要进行查询】

       如果需要通过角色ID查数据可以这样:

       List userListByID=userList.where(o=>o. ID =3);

       通过用户Id查询

       List userListByUserID =userList.where(o=>o. UserID=123);

注意:减少交互次数的基础上,需要根据业务需求 来进行刷选需要的数据、避免每次都是直接查询所有;

4.2多使用存储过程

优点:

.效率要好,因为是已经编译过的,sql要重新编译;

.处理复杂的报表统计的时候,使用存储过程,便于提高效率,以及业务逻辑的处理

缺点:

.不可移植性,每种数据库的内部编程语法都不太相同,当你的系统需要兼容多种数据库时最好不要用存储过程。

. 熟悉写存储过程,否则后期系统维护会产生问题 [重要的是 注意注释清楚用途]

4.3优化业务逻辑

.要通过优化业务逻辑来提高性能是比较困难的,这需要程序员对所访问的数据及业务流程非常清楚。如何实现高性能的数据处理\数据库性能优化_第5张图片

如何实现高性能的数据处理\数据库性能优化_第6张图片如何实现高性能的数据处理\数据库性能优化_第7张图片

 

 

4.3使用batch的提交处理方法,批次处理数据

                            采用batch操作一般不会减少很多数据库服务器的物理IO,但是会大大减少客户端与服务端的交互次数,

                            从而减少了多次发起的网络延时开销,同时也会降低数据库的CPU开销。(尤其避免在循环里请求数据库连接)

 

5、减少数据库服务器CPU运算

5.1使用绑定变量

1、防止SQL注入

2、提高SQL可读性

3、提高SQL解析性能

(绑定变量,如果判断有相同的SQL字符,并且确认是同一逻辑的SQL语句,则从共享池缓存中取出SQL对应的执行计划,根据执行计划读取数据并返回结果给客户端;无需再重新生成一个执行计划,然后根据执行计划读取数据并返回结果给客户端。)

示例:

如何实现高性能的数据处理\数据库性能优化_第8张图片

 

详细说明【如下】

如何实现高性能的数据处理\数据库性能优化_第9张图片

 

当一条SQL发送给数据库服务器后,系统首先会将SQL字符串进行hash运算,得到hash值后再从服务器内存里的SQL缓存区中进行检索,如果有相同的SQL字符,并且确认是同一逻辑的SQL语句,则从共享池缓存中取出SQL对应的执行计划,根据执行计划读取数据并返回结果给客户端。

如果在共享池中未发现相同的SQL则根据SQL逻辑生成一条新的执行计划并保存在SQL缓存区中,然后根据执行计划读取数据并返回结果给客户端。

为了更快的检索SQL是否在缓存区中,首先进行的是SQL字符串hash值对比,如果未找到则认为没有缓存,如果存在再进行下一步的准确对比,所以要命中SQL缓存区应保证SQL字符是完全一致,中间有大小写或空格都会认为是不同的SQL

如果我们不采用绑定变量,采用字符串拼接的模式生成SQL,那么每条SQL都会产生执行计划,这样会导致共享池耗尽,缓存命中率也很低。

 

 

6、编写简洁高效规范的SQL语句

sql查询语句的处理步骤,流程图

如何实现高性能的数据处理\数据库性能优化_第10张图片

如何实现高性能的数据处理\数据库性能优化_第11张图片

 

 

              参考:SQL执行一般顺序

              (8)SELECT (9)DISTINCT  (11)