Github系列文章地址html
原文地址java
一个高性能的数据访问层须要不少关于数据库的内部结构、JDBC、JPA、Hibernate以及不少优化商业应用的技术建议。git
若是你正在使用譬如Hibernate或者MyBatis这样的ORM框架,那么能够参考验证执行语句的效率。另外推荐一个 测试中断言机制 能够帮你在提交代码以前就发现不少的查询问题。github
数据库链接一直是数据库中比较耗时的操做,所以建议是务必使用数据库链接池 机制。另外,数据库链接还受到数据库底层的限制,所以也须要合理有效地释放无用的数据库链接。在性能调优中,咱们常常须要测试而且设置合理的链接池大小。这里推荐一个FlexyPool工具能够帮助你选择生产环境下合适的链接池大小。sql
JDBC Batching容许在单次数据库链接中发送多个SQL语句。这篇博客里进行了对比能够看出Batch操做的性能提高很是巨大 ,不管是在客户端仍是数据库端。 PreparedStatements
是不错的用于Batching操做的选择,像Oracle也仅支持基于PreparedStatements的Batching操做。数据库
JDBC中已经基于PreparedStataement.addBatch
与 PreparedStataement.executeBatch
)提供了Batching操做的辅助,不过若是打算手动的构造Batching操做,那么在设计阶段就要考虑到是否须要引入Batching。若是你用的是Hibernate,那么能够用简单的配置就开启Batching,Hibernate 5.2 提供了 Session级别的Batching, 也是很是方便的。json
Statement Caching算是最不经常使用的几种优化手段之一了,你能够利用PreparedStatements
同时在客户端(Driver)或者数据库端同时缓存语句。api
若是你是使用Hibernate做为ORM工具,那么IDENTITY
生成器可能会影响到你的性能,由于它会禁止掉JDBC Batching。Table
生成器也不是啥好选择,它会使用独立的事务上下文进行捕获操做,而致使底层的事务日志承受额外的压力,而且致使了每次链接池中的新的请求都须要一个新的Identifier。所以笔者仍是推荐SEQUENCE
生成器,SQL Server在2012版本以后也开始支持了该生成器。缓存
在数据库设计的时候,咱们应该尽量地选用合适的列类型,这样可让你的数据库以最合适的方式去索引存储你的数据。譬如在PostgreSQL中你应该使用inet
来存放IPv4的地址,特别是Hibernate还容许你自定义数据类型,这样方面和数据库中的列类型一一对应。性能优化
Hibernate提供了不少的关系映射,不过并非全部的映射都是性能优化的。
咱们在开发的过程当中须要注意避免单向的关系映射,以及@ManyToMany
这种映射。对于集合查询而言,双向的@OneToMany
关系才是值得推荐的。
继承是面向对象的语言中的不可或缺的一部分,但这也是关系型数据库与面向对象的语言之间的不协调最甚的地方。JPA提供了譬如SINGLE_TABLE
、JOIN
以及TABLE_PER_CLASS
来处理继承映射的问题,而这几个办法都是各有千秋。
SINGLE_TABLE
在SQL语句中的表现最好,不过不能使用NOT NULL
约束,数据完整性的控制较差。
JOIN
经过更复杂的语句控制来保证了数据的完整性,只要你不使用多态查询或者@OneToMany
关系注解,那一切还好。
应该避免使用TABLE_PER_CLASS
,它基本上没法生成高效的SQL语句。
在使用JPA或者Hibernate时候,应该随时注意持久化上下文的大小,避免同时管理过多的实体类。经过限制受管实体类的数量,咱们能够更好地进行内存管理,而默认的脏检测机制也会有更好的效果。
获取过多的冗余数据多是致使数据访问层性能降低的缘由之一,即便是包含了投影等操做,对于实体的查询应该也是排外的,即不会引入冗余数据的。咱们应该只获取那些业务逻辑须要到的数据,这里推荐使用DTO Projections。过早的数据获取以及Open Session In View这种反模式都是要被避免的。
关系型数据库使用了不少的内存缓冲结构体来避免大量的磁盘访问,可是咱们每每忽略了数据库缓存。咱们能够经过调整数据库查询引擎,将更多的内容留于内存中以免磁盘查询最终明显的减小响应耗时。应用层的缓存则利用高速副本的方式来保证低响应时间。而Second-Level缓存可以有效减小读写事务的响应时间,特别是在主从复制架构中。根据不一样的应用取钱,Hibernate提供了 READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, 以及 TRANSACTIONAL这几种方式。
在考虑性能和数据完整性的时候,事务隔离层 就变得相当重要。对于并发较高的应用,须要避免更新失败, 可使用 乐观锁或者扩展的持久化上下文.
而为了不 乐观锁中的
false positives, 可使用 无版本的乐观控制或者基于写属性集的实体划分.
虽然你是用了JPA或者Hibernate,可是你能够用一些原生查询,建议是好好利用Window Functions, CTE (Common Table Expressions), CONNECT BY
, PIVOT
等等。这些工具可以避免你一次性传输过多的数据进入应用层,若是你能够把这个操做托付给数据库层进行,那么能够仅关心最终的结果,从而节约了磁盘IO与网络带宽。
关系型数据库可以方便地进行扩展,像Facebook、Twitter、Pinterest这些大公司都扩展了数据库系统:
数据副本与分片是两种经常使用的增长吞吐量的扩展方式,你应该合理的组合应用这些方式从而提升你的商业应用的能力。