1、概述
对一个大问题进行划分处理是计算机领域常见的手段。在数据库应用中,对于一个大表,既可以选择进行水平分区,也可以选择进行垂直分区。水平分区在主流的数据库产品中都得到了实现,垂直分区一般要靠数据库设计人员自行实现(将一个表划分为多个表)。金仓数据库V6在数据库内核中实现了表的垂直分区,它可以简化数据库设计人员的工作,并为应用程序提供透明的SQL访问。
使用垂直分区主要利用了应用对表中字段访问的如下特性:
(1)字段访问频率的不均匀性:即某些字段访问特别频繁,其他字段则访问的较少。可以参考80/20原则。
(2)应用对字段访问的聚集性:即应用中的查询倾向于一起访问某些字段,如a、b、c三列总是一起访问;d、e两列总是一起访问。可以参考局部性原理。
(3)字段访问顺序的依赖性:即应用中的查询按照某个特定的顺序访问字段,例如访问d、e字段前总是先访问a、b、c字段。
在应用对表的访问满足以上特性之一时,使用垂直分区可以使访问/修改这些列的查询不再需要访问/修改其他无关列,从而减少物理I/O。
本文给出了一种根据“应用的访问模式”确定如何对表进行垂直分区(即确定分区表中字段)的思路,并且以一个应用为例。
2、金仓数据库V6中垂直分区实现方法
金仓数据库V6支持基于主码连接的垂直分区,语法如下:
- CREATE TABLE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] [SchemaName.]TableName
- (
- { ColumnName <DataType> [IDENTITY [(Seed, Increment)]]
- [ DEFAULT { NULL | USER | <Expression> } ] [ <ColumnConstraint> ]
- | [ <TableConstraint> ]
- } [, ...n ]
- ) [ <VerticalPartitions> ]
- [TABLESPACE TablespaceName]
- <VerticalPartitions> ::= PARTITION BY COLUMN
- ( [PartitionName]
- ({ ColumnName [, ...n ])
- [TABLESPACE TablespaceName] ) [, ...n ]
垂直分区是按列进行分区,即把一条记录分开多个地方保存,每个分区的行数相同,列顺序与PARTITION子句中的顺序。
包括存放没指定的列的分区,分区数目必须大于等于二,各分区表间允许字段重复,但不能完全重复。
垂直分区基表必须有主码字段,如果分区没有指定主码字段,将在分区中加入基表中的主码字段。
分区表不能有基表字段之外的字段,表中有但分区表没指定的字段默认放入一个新的分区表。
主码字段和重复字段不能指定为IDENTITY。
如果没有指定分区名,系统会自动建立分区名,分区的命名规则为基表名_VP_[1…N]。分区和基表在同一命名空间。
如果没有指定表空间,缺省存放到分区基表所在的表空间中。
不支持建立跨分区的表级约束。
例子:
- CREATE TABLE base (
- col1 INT, col2 INT, col3 INT, col4 INT, col5 CHAR(100),
- PRIMARY KEY(col1, col2)
- )
- PARTITION BY COLUMN (P1(col1, col2, col3, col4), P2(col5));
将会创建名为BASE的基表和P1、P2两个分区表。P1和P2的结构如图所示,两个分区都包含元组控制信息(元组头)、各分区的分区列和作为连接索引的主码列col1和col2。
3、分区方案的选择
在决定如何分区选择时首先要了解应用的场景,然后考虑分区对I/O的影响:
了解应用场景(可以在应用开发过程中进行)
获得应用中包含的全部查询;
记录查询的顺序;
标记查询执行的次数(或者是百分比);
记录查询平均访问的元组数;
看是否有满足使用垂直分区的场景
将查询按照涉及的表分组(涉及多个表的出现在多个组中);
对每一组查询,做一个表格,表格的列是该组查询涉及的表的列和列长度,表格的行是查询;
对于该组每一个查询,标记该查询涉及的列;
结合查询的频率和访问元组数粗略查看是否有满足使用垂直分区的场景;
计算I/O量获得分区方法
在满足场景的组中选择几个分区方案,包括分区的类型和列的组合。
根据分区类型计算各分区的元组I/O量。
注意尽可能考虑访问模式,即查询执行顺序带来的物理I/O差别。可能带来的差别有:
1)去掉重复计算IO。例如一个涉及分区P1的查询后会接着执行一条更新该分区的语句,则更新语句的读就不会是物理读。
2)考虑命中率问题。不同分区的页面命中率需要根据分区的访问频率进行估计。
计算不分区方案和每个分区方案的I/O量,I/O量为查询数*元组数*该分区元组I/O量。
比较选择I/O量最小的方案。
验证分区带来的I/O减少
可能会有实际情况与计算不符的情况发生,因为计算中的I/O量是逻辑I/O量而不是准确的物理I/O,实际测试每种方案,收集统计信息(每张表的读写信息、页面的命中率),根据实际值调整方案。
4、实例:TPC-C的垂直分区选择
TPC-C是一个典型的OLTP类型的负载。TPC-C测试中共有9张表,包括c_warehouse、c_customer、c_district、c_stock、c_order、c_order_line、c_item、c_history和c_new_order;另外,共有5种事务场景:new order、payment、order-status、delivery和stock-level,其中order-status和stock-level是纯查询事务,其它是以更新为主的事务。
分析5种事务包含的查询,除去c_warehouse、c_distric表等小表,以及更新较多的大表,如c_order和c_order_line,我们可以知道在c_stock表和c_customer表上进行垂直划分可以带来较大效率的提升。我们可以根据实际待测试的环境,按照前面描述的原则进行垂直划分方案的设计、测试和验证。