浅谈SAP HANA中Column Table的OLTP性能优化
目前市面上的数据库产品,由于受限于自身设计架构,在实现OLTP(Online Transaction Processing, 联机交易处理)和OLAP(Online Analytical Processing, 联机分析处理)上都存在一定的倾向性。从性能角度考虑,必须舍弃一方以达到另一方的良好展现,数据存在于不同数据库中,这使得大部分企业的交易系统和分析系统都是独立存在的,给企业的信息化造成一定的阻碍。
SAP作为全球企业信息化的龙头软件企业,出于对该问题的考虑,在设计新一代内存数据库产品SAP HANA时,其初衷就是为了实现企业应用中OLTP和OLAP系统的结合。在SAP HANA中引入了“列存储”表的概念,这种存储方式的表与传统的“行存储”表的区别在于:“行存储” 表的每行记录在内存地址中是连续存放的;而“列存储”表的每一列数据在内存中是连续存放的。这种区别造成了 “列存储”表在OLAP上,例如针对某个字段进行聚合函数操作时候具有非常好的性能,而在进行OLTP上,则因为需要实时调整内存中的数据存放结构,所以在性能上会有所影响。
为了解决“列存储”表在OLTP上的性能问题,SAP HANA给每一张表都开辟了名为“Delta”的区域,与表的主存储区相对应。该区域内部是行式存储的,OLTP的更新数据都会先存放到该区域,因此会比直接写入到列存储区上性能要好。在达到某些条件的时候,Delta区域会和主存储区的数据进行合并的操作,将行式的数据转成列式的数据存储。以上所述的Delta区域是SAP HANA数据库的自身架构设计,可以一定程度上解决与完全的行存储表在OLTP性能上的差距。而从应用角度出发,还是有很多的 设计方法可以进一步提升“列存储” 表的OLTP性能。
1. 关闭表的自动Delta Merge功能
前面提到,“列存储”表在Delta区域中的数据达到一定程度时,会和主存储区做“Merge”的操作。在进行这种操作的时候,会将目前的Delta区域锁定,即任何的OLTP操作都会被阻塞住,不能再向该区域进行数据更新。在“列存储” 表建立的时候,“Delta Merge”是自动打开的,因此很难预料到在何时会进行“Merge”操作,如果在进行“Merge”操作时有很频繁的OLTP操作,会对性能产生巨大的影响。
这里,推荐的做法是,在常用的会进行OLTP操作的表上将自动“Delta Merge”功能关闭。可以用如下的sql命令来实现:
alter table [table_name] disable automerge
当然,也可以用如下的命令来开启自动“Merge”功能:
alter table [table_name] enable automerge
之后数据库会定时查看Delta区域是否满足merge条件,以决定在后续的某个时间点进行merge操作。
由于Delta区域的数据是行存储,而主存储区的数据是列存储,如果此时进行表查询,表关联之类的操作,由于存储格式的差异,数据库会在两片区域内寻找匹配加工数据,在column和row engine之间不停切换,会对性能产生不利影响。所以在Delta区域中数据达到一定程度时,或者再某段频繁的OLTP操作结束之后,可以手工对表进行“Merge”:
merge delta of [table_name]
2. 多线程
由于OLTP大部分都是比较轻量的数据库级操作,消耗的时间基本都是秒级以下。因此在单线程情况下,性能的提升十分有限。在insert/update/delete某条记录的时候,数据库对于该表只会有行级锁,由于不同记录之间没有依赖性,所以利用多线程并行不会有堵塞的情况发生操作,反而会减少CPU等待时间以及数据库响应时间,这会对性能有十分显著的提高。
一般来说,随着开启的线程数量的增加,性能会有线性的提升。但受到数据库自身以及数据库服务器的配置的局限性,到后面性能提升的效果会逐渐减弱,直至最后趋于平衡。
开启多线程有多种方式,可以在JDBC或ODBC开启多个connection,也可以利用SAP HANA自带的hdbsql命令,通过shell脚本异步调用多个hdbsql命令,达到并行的效果。
针对于单条记录的OLTP操作,只需要开启多个数据库的连接,就可以达到并行的目的。但可能还存在需要批量插入很大数据量的操作,例如insert into [table1] select * from [table2], table2的数据量很大,如果直接使用该语句只能够用到单个线程。这时候必须要从数据本身入手,看是否有某些字段可以进行物理拆分。例如如果表中有ID的数字字段,可以通过ID的某位数字[0-9]进行物理拆分,将大的insert操作拆分成insert into [table1] select * from [table2] where ID like ‘%[0-9]’这样的多条insert语句来执行,此时多条语句就可以充分利用到多线程了,此时性能也会有较为显著的提高。
3. 表分区
SAP HANA中可以对“列”存储表进行分区(partition)划分。建立表分区有几个优势:
- 数据分布在各个分区内,可以充分利用多线程,各线程负责从某一个分区内处理数据,达到并行效果。
- 可以针对业务场景划分表。例如将若干年的销售数据通过月份进行分区,那么如果需要进行某月销售记录的分析时,只需要从某个分区取数据,减少取记录的数据量。
- 让OLTP更新的数据散落在不同分区,避免对同一块数据区域频繁操作。
SAP HANA提供了三种分区方式:Hash分区、Range分区以及Roundrobin分区。前两者是针对某个或联合字段进行分区,区别在于hash分区是对字段的哈希值进行分区,而range分区则是定义了字段的取值范围。一般来说,如果涉及到年月日时间字段的数据,可以考虑通过Range分区,将数据划分到月或日的区间内;如果例如客户ID号这样的字段数据,可以考虑Hash分区,在真实系统中,ID号这样的自增数字字段,按照Hash值划分在可以达到较好的均匀分布。Roundrobin则是针对整张表记录进行随机划分,将数据按记录条数均匀分配到分区之中。
表分区一般会和多线程结合起来使用,以达到最佳的性能。不仅仅是事务性操作可以分多线程来处理; delta merge的操作也可以针对于某一个表分区,因此也可以利用多线程并行来merge表:
merge delta of [table_name] part [partid]
当然,建立分区也会带来一定的代价。存储表数据所需要的data volume和log volume都会有所增加。
4. JDBC优化
SAP HANA提供了ODBC、JDBC、MDX等数据驱动方式,供外部程序调用。其中MDX主要用于模型数据的获取展现,对于OLTP操作来说,主流的数据驱动方式还是ODBC和JDBC。这里主要以JDBC为例谈一谈如何提高SAP HANA中OLTP的性能。
1. 关闭自动提交
自动提交模式每次执行SQL语句都将执行自己的事务,并且在执行结束提交。关闭之后可以将一组数据库操作放在一个事务中。
2. 增加commit的数据条数
在事务性操作过程中,每一次提交都会产生一定的数据库开销。在实际场景允许情况下,尽可能减少commit的次数会减少无谓的开销,从一定程度上提升性能。
3. 采用batch方式提交
在JDBC中,可以定义batch的提交方式,这种方式可以减少数据库数据传输的往返次数,从而提高性能。
conn = DriverManager.getConnection (connection, username, password);
stmt = conn.createStatement();
stmt.addBatch(sql);
stmt.executeBatch();
想获取更多SAP HANA学习资料或有任何疑问,请关注新浪微博@HANAGeek!我们欢迎你的加入!
转载本文章请注明作者和出处http://scn.sap.com/community/chinese/hana/blog/2014/04/15/%E6%B5%85%E8%B0%88sap-hana%E4%B8%ADcolumn-table%E7%9A%84oltp%E…,请勿用于任何商业用途。
good jobs, great learning material. Thanks for sharing.