在大多数的开发项目中,尤为是集成项目,都会有涉及到数据分析部分的工做,数据分析多数是各类图表的展示和交互(所谓数据可视化),数据分析的展示速度直接影响着用户的体验,并且绝大多数管理系统(MES、PDM/PLM、ERP、SCM、OA、HR等等)的数据都存储在数据库中,数据库相关的性能优化能够较容易提升程序系统的总体性能、提高用户的体验,保障项目的顺利验收。对应用程序进行总体的性能优化须要全局考虑,好比:硬件选型、软件架构、部署架构、程序开发等方面。本文主要侧重介绍程序开发部分的数据库层面的相关优化手段,但愿能对你们有所帮助。java
不管是开发项目仍是集成项目最终的目的是项目的验收,促进项目的回款,保障公司的资金流进一步的运做。可是若是功能程序的性能不过关,响应速度慢进而影响客户的体验,则直接影响着项目的验收,从而阻碍了公司的正常运做。典型的优化途径有:硬件选选型、系统软件、应用程序三个途径。sql
选择什么样的服务器都会遇到一个相同的问题,那就是选择什么硬件配置的服务器。在平常的项目工做中会将服务器区分为:应用服务器、数据库服务器、文件服务器以及其余服务器。数据库
一般状况下硬件配置越高,性能越好,可是综合考虑(money!)硬件配置通常能知足展望将来3-5年性能要求便可。注意:云服务器如今也是能够考虑的选择。apache
在操做系统的选择上最多见的就是Linux以及Windows,考虑到服务器的性能、安全性一般咱们选择Linux操做系统。虽然Server版本操做系统自己的性能已经相对稳定,可是咱们能够优化对应操做系统的配置来进一步匹配对应项目的性能需求,而Linux系列的操做系统相对来讲有更多的优化策略和空间,更重要的是运维尤为远程运维很方便。缓存
衡量一个程序的标准首当其冲的是程序的安全性,而后则是程序的性能,也就是程序的响应速度。对于程序的保密性要求并非全部行业均是严格要求的那么对于程序的性能则是不区分行业均是更改的性能带来更好的体验。安全
应用程序的优化必杀技一般来讲就是程序(软件)自己支持水平扩展,不少书籍都有介绍,百度关键字:大型系统架构,能够了解不少相关知识,水平扩展是另一个话题,这个话题也会涉及到不少方面,在本文中就不一一赘述。性能优化
系统程序的基础环境调优对应用程序的优化也较为明显,好比:Java程序的JVM设置、PHP程序的子进程数配置、.NET程序的认证机制、运行库设置等等。基础环境调优也不是本文阐述重点。在下面咱们主要对软件数据库相关的优化方案中进行详细介绍。服务器
虽然NoSQL也开始流行,可是更多场景下它只是数据库的补充,数据库自从诞生开始起就紧紧占据着管理软件后台存储的主场,并且从未离开。数据库层面的性能优化属于短平快调整就能见效、或者在开发中稍微注意就能够大幅度提高性能的常规系统调优手段。架构
咱们一般须要从总体策略发的角度出发,将数据库调优从汇总查询、视图方式、数据缓存等三个方面来进行。并发
在平常工做中若是所涉及的查询语句较为复杂,或者须要访问第三方的数据库,而在访问第三方数据库时经常会由于不一样的数据库中不一样数据表的读取频率不一样,进而影响性能。面对这种状况咱们一般将须要查询的内容汇总到中间表,而后直接从中间表进行数据查询。
通常状况下建立视图是不会直接提升性能的,可是若是须要查询的内容涉及到多个数据表之间的关联且关联关系较为复查,查询出的结果集被高频的访问。这时若是没有建立视图那么每要查询这个结果集就须要从新建立SQL,可是若是建立统一的视图而且在建立视图是已经进行SQL调优,方便你们的统一调用从而来提高数据库的性能。
当前查询结果的结果集是为展示内容提供数据展示,不是交互性数据操做,不常常被改变是咱们能够将数据的查询结果集放入缓存中,这样在读取时在缓存中进行获取,减小了对数据库的访问操做进一步的提高程序的响应速率。在程序应用中常见的缓存处理手段以下:
静态缓存
静态缓存一般为建立一个静态的HashMap 变量,在数据获取是判断Map中是否含有,若是有在Map变量中获取,若是没有则在数据库中查询而后放入缓存的Map变量中。
分布式缓存
分布式缓存一般是应用于集群部署的场景,一般应用部署于不一样的业务服务器,经过Redis 或者Mncached来进行分布式缓存的管理。
在数据库优化的方案中最多见也是性能优化的最关键的部分就是数据库的SQL优化,本篇文章分别在查询优化、更新优化、其余说明三个方面来进行说明常见的SQL优化。
避免在客户端返回大数据量
尽可能避免在客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。若是必定要返回大数据量,考虑使用数据库分页来处理。
查询避免使用*号
SELECT子句中避免使用*号数据库在解析的过程当中,会将*依次转换成全部的列名,这个工做是经过查询数据字典完成的,这意味着将耗费更多的时间。如:
Select * from emp |
应该为:
Select id,name,code from emp |
慎用DISTINCT
用EXISTS替换DISTINCT: 当提交一个包含一对多表信息(好比部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT. 通常能够考虑用EXIST替换, EXISTS 使查询更为迅速,由于RDBMS核心模块将在子查询的条件一旦知足后,马上返回结果. 例子:
(低效):
SELECT DISTINCT DEPT_NO,DEPT_NAME FROM DEPT D , EMP E WHERE D.DEPT_NO = E.DEPT_NO |
(高效):
SELECT DEPT_NO,DEPT_NAME FROM DEPT D WHERE EXISTS ( SELECT ‘X' FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO); |
UNION和UNION-ALL
用UNION-ALL 替换UNION ( 若是有可能的话): 当SQL 语句须要UNION两个查询结果集合时,这两个结果集合会以UNION-ALL的方式被合并, 而后在输出最终结果前进行排序. 若是用UNION ALL替代UNION, 这样排序就不是必要了. 效率就会所以获得提升. 须要注意的是,UNION ALL 将重复输出两个结果集合中相同记录. 所以仍是要从业务需求分析考虑使用UNION ALL的可行性。
条件子句的注意事项
建立索引
对where中的条件列建立索引,能够加快查询速度。对于表中的主键、外键、有对像或身份标识意义的字段视状况添加索引。
避免null判断
应尽可能避免在 where 子句中对字段进行 null 值判断,不然将致使引擎放弃使用索引而进行全表扫描,如:
select name from system_users where id is null |
最好不要给数据库留NULL,尽量的使用 NOT NULL填充数据库。备注、描述、评论之类的能够设置为 NULL,其余的,最好不要使用NULL。不要觉得 NULL 不须要空间,好比:char(100) 型,在字段创建时,空间就固定了, 无论是否插入值(NULL也包含在内),都是占用 100个字符的空间的,若是是varchar这样的变长字段, null 不占用空间。
能够在id上设置默认值0,确保表中id列没有null值,而后这样查询:
select name from system_users where id = 0 |
避免不等于操做
尽可能避免在 where 子句中使用 != 或 <> 操做符,不然将引擎放弃使用索引而进行全表扫描。
避免in或not in
in 和 not in 也要慎用,不然会致使全表扫描,如:
select id from t where num in(1,2,3) |
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3 |
不少时候用 exists 代替 in 是一个好的选择:
select num from a where num in(select num from b) |
用下面的语句替换:
select num from a where exists(select 1 from b where num=a.num) |
避免对字段进行函数操做
尽可能避免在where子句中对字段进行函数操做,这将致使引擎放弃使用索引而进行全表扫描。以下:
select id from t where substring(name,1,3) = ’abc’ |
查询全部以abc开头的名字的id
应改成:
select id from t where name like 'abc%' |
更新批量使用bach处理
在程序中尽可能避免大量的insert或者delete同时处理,若是遇到这种状况须要使用bach进行批量统一处理。
避免大批量的insert和delete
由于这两个操做是会锁表的,表一锁住了,别的操做都进不来了。因此,若是有一个大的处理,必定把其拆分,使用 LIMIT oracle(rownum),sqlserver(top)条件。
Update注意
若是只更改一、2个字段,不要Update所有字段,不然频繁调用会引发明显的性能消耗,同时带来大量日志。
杜绝count(*)
select count(*) from table; |
这样不带任何条件的count会引发全表扫描,而且没有任何业务意义,是必定要杜绝的。
在数据库使用中尽可能减小长事务
在数据库中若是涉及到主表、从表、附属从表,这时若是同时操做三个数据表同时成功以及同时失败,若是当前数据表的数据量较大,为了下降数据库的性能压力,咱们能够采用批处理方式分别批处理三个数据表来进行数据库性能的提高。
减小分布式事务的使用
通常的数据库均是支持分布式事务,当涉及到跨数据库的不一样数据表的操做时咱们可使用分布式事务。但为了提升性能损耗,尽可能减小这种强一致性需求,更多状况下转化为最终一致性方式来知足业务需求,一般来讲引入消息中间件是这种场景下的常规解决手段。
多用varchar和nvarchar
尽量的使用 varchar/nvarchar 代替 char/nchar ,由于首先变长字段存储空间小,能够节省存储空间,其次对于查询来讲,在一个相对较小的字段内搜索效率显然要高些。
减小大字段的使用
在数据库中定义类型是尽可能避免使用大字段类型如:BLOB、TEXT、LONG以及Object等大对象的类型
不要在数据库中存储文件
在程序设计以及数据库存储是不要将图片文件、其余日志文件的文件类型存储于数据库中,而是在数据库中存储文件索引的URL将文件存储于文件服务器中。
在进行数据库链接操做时,咱们能够经过选择合适的驱动、释放链接池中的资源、选择符合应用场景的接口,构造只读结果集来进一步的优化JDBC的配置。下面咱们经过链接处理、匹配接口以及返回结果三个方面进行详细的说明。
对于Java程序而言, Connention的优化一般使用数据链接池(dbcp、proxool、c3p0)来进行Connention对象的管理,这样程序的灵活性强,便于移植。但要注意的是对象池里中是没有回收机制,而且对象池里有容量限制,对于对象池里的闲置对象尽早的释放资源。
下面来简单说明不用的链接池的对比:
Dbcp(DataBase connection pool):是apache上的一个 java链接池项目。
优势:配置方便,能够设置最大和最小链接,链接等待时间等,持续运行的稳定性,速度快。
缺点:没有自动的去回收空闲链接的功能,大并发量的压力下稳定性不高,不可以进行链接池监控。
Proxool:Proxool是一种Java数据库链接池技术。是sourceforge下的一个开源项目。
优势:能够设置最大和最小链接,具有监控功能。
缺点:明显的性能问题持,续运行的稳定性不高。
C3p0:是在Hibernate和Spring中默认支持该数据库链接池,实现了数据源和jndi绑定,支持jdbc3规范和jdbc2的标准扩展。
优势:支持高并发,异步操做,有自动回收空闲链接功能。
缺点:没有Dbcp的速度快。
对于Statement对象的优化,咱们须要根据不一样的应用场合选择合适的Statement接口。如:
Statement:不带参数,例如:查询时,不须要到任何参数。
PreparedStatement: PreparedStatement能够写参数化查询,比Statement能得到更好的性能,能够阻止常见的SQL注入式攻击,提升安全性。
CallableStatement:专门针对存储过程,使用它能享受到全部存储过程带来的优点,但也包括存储过程带来的劣势如Java程序可移植性查,依赖数据库等。
优化结果集(ResultSet)查询时候,返回的结果集有不一样的类型。结果集分两种类型:只读和可更改。返回的结果集默认就是只读的。而在Oracle中咱们能够设置手工加锁语句(Select XXX forUpdate)。
明确指定主键,而且有此数据则锁定若无则不锁定
SELECT * FROM products WHERE id='3' FOR UPDATE; |
无主键或者主键不明确则进行表锁定
SELECT * FROM products WHERE name='Mouse' FOR UPDATE; |
应用程序优化是一个系统工程,须要综合考虑,更多时候要提早考虑,在系统架构层面来保障系统具备更多优化的能力。系统运维有一种消极的说法,系统能用就行,不要轻易去改变;但对于系统开发而言,每一次代码重构都是一次系统调优以及加强调优能力的机会。Devops也慢慢开始盛行了,开发和运营愈来愈密切,甚至是一套班子两种角色,你(们)如何选择?我我的而言,倾向主动调优、拥抱变化,即使可能带来一些风险。
不管是对公司的产品进行开发仍是在项目开发的过程当中,要在全局的角度出发总体考虑、制定规范、落实到每一项的工做中,从制度上保障系统性能调优的能力。笔者做为数通畅联公司的一名技术员工,今天将本身所学所用的常见的数据库优化相关处理总结出来与你们分享。若是对本文档相关的描述信息存在疑问欢迎加入数通畅联官方技术群(299719834)进行讨论。