Trafodion 性能优化之DDL

来源:互联网 发布:java的string不可变 编辑:程序博客网 时间:2024/04/28 16:30

影响Trafodion数据库性能的因素有很多,这也包括是否创建一个合适的表。创建表的时候有很多因素会影响到性能,下面就一一介绍一下建表时需要考虑的因素。

1 选择一个好的主键(Primary Key)

Trafodion中的表是按簇键(Cluster Key)顺序存储的,所以我们通常认为Trafodion的表本身也是一个索引。主键是具有唯一约束的特殊簇键。我们应优先选择那些在WHERE过滤中经常用到的字段作为主键或簇键字段。主键或簇键可以包含一个或多个字段,字段的先后也是非常严格的。主键或簇键的设计一般要遵循以下规则,
(1) 键应尽可能短,尤其是表不使用Aligned Format的时候。
[1] Key中应尽量避免使用CHAR/VARCHAR类型,尤其是比较长的字段。如果CHAR/VARCHAR字段是UTF8格式,尽量使用”n BYTES”而非”n CHARS”,避免为每个字符分配4个bytes。
[2] 不要因为唯一性要求而把Key弄的太长。唯一性可以通过以下一些方式实现。
(2) 如何不适合创建Primary Key,下面提供一些方法保证Key的唯一性。
[1] 使用Store By代替,Store By会生成一个隐藏列”SYSKEY”作为Key的最后一个字段。SYSKEY在每一行都是唯一的。
[2] 使用一个CHAR(16)类型的字段作为Key的最后一个字段。当表有数据插入时,使用unique_id()函数生成一个唯一值。
[3] 使用IDENTITY。对于批量插入如Bulk Load或Upsert需要把Cache Size设置大一些(默认25太小)。
(3) 尽量把UEC(Unique Entry Count)低的字段放在Key的最前面,这可以增加使用MDAM的可能性。如果Key有多个字段,把UEC最低的放在最前面,较低的放在第二位,依此类推。
(4) 一个好的簇键需要满足以下需求,
[1] 均衡分布表的Regions,通常使用Salting实现。
[2] 冷热数据分离,通常使用Divisioning实现。
[3] 提升主要查询语句的性能。
(5) 空值也可以作为Key的一部分(默认情况下Key不允许空值),可以通过cqd ALLOW_NULLABLE_UNIQUE_KEY_CONSTRAINT ‘ON’实现。对于空值,HBase对每个列需要额外使用一个byte来存储。

2 选择一个好的分区键(Salting Key)

Trafodion允许在主键或簇键的子集上进行Salting(盐粒分布)。Salting的目的是把数据均衡分布到不同的Region服务器中,从而避免查询热点问题(只从单个Region服务器查询)。Salting会生成一个hash值作为Key的前缀。如果查询语句的WHERE条件中包含Salt中的字段,那么查询很可能只需要查询对应的Region区域。默认情况下,Salting字段即主键或簇键所有字段,不过也可以选择部分字段作为Salting字段。选择Salting键的原则一般如下,
(1) Salting Key字段组合的UEC必须至少是表partition个数的100倍或更多。表中列的UEC可以通过先更新表的统计信息再通过SHOWSTATS查询。
(2) Salting Key不能要严重的数据倾斜。数据倾斜会导致数据分布不均从而导致查询性能问题。可以使用SELECT “SALT”, count() from group by 1 order by 2; 来查看数据倾斜问题。数据倾斜也可以在数据加载前通过SELECT HASH2PARTFUNC(,,.. FOR ), count() from hive.hive. group by 1 order by 2; 查询(如果源数据在hive里面,M表示Salt partitions的个数)。
(3) 最具有代表性的OLTP查询是WHERE条件中Salting Key中的每个字段都有”=”限制,这样查询会只定位到某一个或很少的几个region上面。
(4) 基于上述3个条件,尽量选择一个最少的Salting Key的字段组合。
(5) 对于join较多的表,根据经常使用的join字段对表进行Salting,这可以使得只关联到指定的region。

3 列类型(Column Type)

列类型一般由用户定义,但也有一些原则对性能有所帮助,
(1) 对于长度少于25bytes的字符类型尽量使用CHAR而不是VARCHAR,因为VARCHAR会额外使用2个或4个bytes来记录每个VARCHAR值的长度。对于VARCHAR,读取每一行数据需要额外获取字符串长度的时间,因此CHAR更适用于窄的列。
(2) 对于CHAR/VARCHR类型,优先使用UTF8格式。如果要存储二进制类型,使用ISO88591格式。对于Unicode数据可以使用UCS2。
(3) 如果使用UTF8格式,定义最大size为BYTES而非CHARS。默认情况下最大size表示最大CHARS个数,所以要使用( CHAR(N BYTES) CHARACTER SET UTF8)。
(4) 对于date或者timestamp格式的数据,使用DATE或者TIMESTAMP类型。我们有很多日期相关的函数可以直接在日期类型上面使用。
(5) 如果列上面不可能有空值,把列定义为NOT NULLABLE。因为对于每一列空值需要一个额外的byte来存储空值指针。

4 多温度数据分离(Division)

对于包含时间序列数据的表最典型的情况是timestamp是Key的一部分。但如果把timestamp字段作为Key的前置列的话会导致后面的字段几乎没什么用,因为timestamp字段的UEC很高。使用DIVISION BY子句可以把timestamp字段的一部分(如天、小时、星期)作为Key的一部分。这种方法可以把较老的数据单独存在region的一端,而最新的数据在另外一端。Divioning的一般原则如下,
(1) 选择一个Divion by interval(YEARMONTH,DAY,HOUR,..),假设大部分的查询都是查询一天或几天的有价值的数据,这个时候就比较适合使用Division By了。语法是DIVION BY (DATE_PART ‘DAY’,)。
(2) 对于时间序列数据用户经常更多的希望看最近的数据。如果查询带LIMIT N或是FIRST N子句,可以把表设计为DIVISION BY … DESC。
(3) 对于表上面有Divioning,”Striped Compaction”方式一个不错的选择。

5 分区个数(Num of Partitions)

HBase表在表数据量增长时会自动Split。如果能在建表的时候进行预分区,可以防止在业务繁忙的时候频繁Split。表的region个数可以通过region最大尺寸推断(默认一个region大小是10G,可以增大到100G)。可以在Salt子句中定义建表时创建多少个region。对于表的扫描,并发度的最大值等于partition的数量。一般设置表的最大region数为8*nodes,比如总共有6个nodes,那么最大的region数为8*6=48个。设置分区数一般原则如下,
(1) 在每个region服务器中尽量多的创建region。

6 行格式(Row Format)

Trafodion支持两种行格式,默认行格式及Aligned格式。对于默认行格式,表中的每个列都是一个单独的HBase Cell,而对于Aligned格式,整个行是一个HBase Cell。关于选取哪一种格式有如下原则,
(1) 如果通过insert或upsert(非bulk load)往表插入数据,对于窄表,Aligned format可以达到2~3X性能提升。
(2) 当表上面的Key越大或表上有很多的较窄的字段(<25 bytes)时,Aligned format性能提升会更明显。
(3) 如果表需要频繁更新,则Aligned format的性能更差,由于更新要对整个行进行修改。
(4) 如果查询只涉及表的很少几列时,Aligned format可能性能会较差,因为需要获取整行数据。
(5) 对于表数据少于一百万或者没有加载数据需求的窄表,行格式选择哪种意义不是很大。

7 HBase存储参数(HBase storage Options)

建表或建索引有一个可选项称为HBASE_OPTIONS。下面是一些可选项对性能有所帮助,
(1) COMPRESSION –每个表或索引都可以有这个选项。最常用的是SNAPPY,GZIP方式比SNAPPY有更好的压缩比但消耗更多的CPU。
(2) DATA_BLOCKENCODING –对于默认行格式非常重要,对Aligned format也有好处。最常用的是FAST_DIFF。
(3) MEMSTORE_FLUSH_SIZE –对于使用upsert导入表时,默认的memstore flush size可能太小了,这时建议把大小设为0.5G或1G。注意Flush size是针对每个region的,因此如果一个表在同一个region服务器上面有多个region,总的memstore空间要把相关的region的size相加起来。较大的memstore flush size可以减少minor compaction的数量。
(4) IN_MEMEORY –对于小表或中等规模的表设为true,把数据缓存在内存中从而提升查询性能。
(5) DURIBILITY –HBase写数据在高吞吐量的时候,WAL写进程可能会成为一个瓶颈。对于需要大量Trickle Load的情况下,把这个值设为SKIP_WAL,可以禁止WAL写日志,不过遇到在Load的过程集群出现故障则数据不可恢复。
(6) SPLIT_POLICY –略

8 二级索引(Secondary Index)

Trafodion支持在表上建立二级索引,索引可以提升查询性能,但会影响插入、更新和删除的效率。正常情况下大部分查询应该都是基于主键或簇键查询的,如果有其他一些查询在非主键列上查询,这时候可能就需要二级索引了。索引创建默认是Aligned format,如果希望是默认行格式需要使用一个cqd。创建索引的时候需要注意几点,
(1) 索引可以和基表一样进行Salting(Salting列一般和基表一致)以实现并发查询,语法为”SALT LIKE TABLE”。索引上面也有DIVISON LIKE TABLE子句。
(2) 每个索引的key包含了基表的key的所有内容。
(3) 如果是Bulkload且每一批新的数据都不会重复,可以使用cqd TRAF_LOAD_ALLOW_RISKY_INDEX_MAINTANENCE来提升插入index的速度。如果没有这个cqd,默认情况下Bulk load需要从scratch重建索引。
(4) 如果表上有索引,upsert会明显变慢。同时,如果表上有索引,insert速度会比upsert要快。

1 0