本文将和大家探讨用纵向和横向这两种方法来组织数据库中的数据。本文的例子都是在Oracle数据库中完成的,但也适用于其他任何关系数据库。这些关系数据库数据组织的方法有利也有弊,文本也将为大家分析它们的异同。
根据业务和发展的需求,可以实施多种不同的数据存储方式。第一种数据布局为横向结构。这是一种传统的数据存储方式。顾名思义,每条新的数据记录都作为一行输入到表中,表字段是横向排列的。第二种是纵向结构。这是一种特殊的数据存储方式,只有由键(Key)和值(value)组成的两个实际数据列,以及一个(也可以是多个)识别列(ID)。
纵向vs.横向
下面的例子是传统的横向表结构:
表HR
ID |
姓 |
名 |
部门 |
性别 |
123 |
李 |
凯 |
技术部 |
男 |
234 |
金 |
鑫 |
市场部 |
男 |
456 |
欧 |
欣 |
会计部 |
女 |
而下面这个是纵向表结构的例子,存储的数据和上面的横向表相同:
表 VR
ID |
Key |
Value |
123 |
姓 |
李 |
234 |
姓 |
金 |
456 |
姓 |
欧 |
123 |
名 |
凯 |
234 |
名 |
鑫 |
456 |
名 |
欣 |
123 |
部门 |
技术部 |
234 |
部门 |
市场部 |
456 |
部门 |
会计部 |
123 |
性别 |
男 |
234 |
性别 |
男 |
456 |
性别x |
女 |
我们可以看到,数据从一个3行×4数据列的矩阵(表HR)转变成了一个12行×2数据列的矩阵(表VR)。横向表的记录条数与列数的乘积似乎和纵向表的行数相等。例如:3×4=12。不过,这种假设并不一定是正确的,稍后会在文中讨论这个问题。
纵向数据存储的利与弊
传统横向方式存储数据可以带有预先设定的结构和列,所以有很多优点,但也有缺点。假设我们设计的应用程序带有一个窗体显示区,而这个显示区是完全动态化的,且没有固定的字段号码或名称。用户可以即时创建一个新的字段,并赋予该字段名称和值。要怎样才能在数据库中长期存储这样的窗体呢?
又假设我们需要根据业务要求来创建一些窗体,各个窗体具有一些符合特定业务需求的不同的字段。我们要把各个窗体的数据都存储在一个横向结构表中,该表中给每一个字段分配一个特定的列,而每个窗体就是该横向表的一行。经过一段时间以后,由于业务需求需要对某个窗体添加一个新的字段。为了将新字段添加到窗体中,就必须改变用户界面和持久层逻辑,而且实际存储的表还需要为此添加额外的列,这样该应用程序还需要重新进行测试和调配。在一个开发人员没有权限直接访问数据库的环境中,数据库管理员团队也要参与到表的实际修改操作当中。如果只需要修改一次也就罢了,但是如果过一段时间后又需要添加另外一个字段呢?
要解决上面提到的两种情况,就需要使用纵向数据存储方式,并在应用层和用户界面上采用一种不同的动态逻辑。因为数据能够以“键/值”配对的形式存储在只有两列的表中,并通过单一的ID的形式将数据通通绑定在一个逻辑窗体中,而且对于能够在一个窗体中设置多少字段并没有限制。而后,纵向表中的每个逻辑行的字段数就可以不一样了。由此可见,纵向数据存储结构的最大好处就是灵活性,不过也有很多弊端。
首先,虽然弹性是有了,但失去了对数据的控制权,也就是说很难维持数据的规范化。举个例子,如果我们在一个纵向表中存储了一个共同基金的信息,根据分析师的名字和联系方式都能够对这些信息做出修改;而通常情况下,这种类型的信息都是存储在不同的表种,并通过外键ID连接到基金表的。而且,在纵向表中,字段的数据类型设置也会出现问题。因为在“值”这一列,只能设置成一种数据类型(例如,设置成varchar),而所有的值都必须是这种类型的值,或者你也可以在保存和检索操作中不停来回转换数据类型。此外,在纵向表中不可能存储类似于BLOB和CLOB这种特殊类型的数据。
纵向表还有一个缺点就是数据的一致性问题。将所有的列名都输入到一个“键”列中,使用户(或应用程序)能够很轻易就把相同的数据存储成不同的“键”和“值”。例如,用户可以创建一个新字段,命名为“公司”,赋予其值为“甲骨文”;而其他用户可能将字段名改为“企业”,而值为“甲骨文”,事实上两个用户的数据是相同的。
此外,要管理和操作纵向表很有难度。要找到并确定一个逻辑行,需要进行多次自连接操作。因此,很少有商业报表软件能够利用纵向表来生成任何有意义的报表。
例如,以上面的表为例,要从横向表中获取所有男性雇员的记录,我们可以使用以下的select语句:
Select * from HR where 性别 like '男'
而要从纵向表中获取同样的数据,我们就需要进行自连接查询,先获取ID,然后获取数据:
Select * from VR where id in (Select id from VR where key = '性别' and value = '男') |
很多开发人员会编写一些特别的函数或存储过程将纵向结构表转换为横向结构,只有这样做,他们才能做出报表,并能够更容易地使用这些数据。
纵向表分组
纵向数据存储的变体能够引入自定义算法把逻辑数据行聚类。这意味着可以使用两个或以上ID列来作为分组属性。例如:
ID |
分组 |
KEY |
VALUE |
123 |
1 |
姓名 |
李丽 |
123 |
1 |
电话 |
22221111 |
123 |
2 |
机器 |
HP 520 |
123 |
2 |
供应商 |
Verizon |
234 |
1 |
姓名 |
马军 |
234 |
1 |
电话 |
33334444 |
234 |
1 |
电子邮件 |
m@mail.com |
243 |
2 |
机器 |
IBM T61 |
当生成自定义报表时,可以很容易地根据第二个“分组”列来将不同的内容分割到不同的页或不同的区域内。因此,上面的纵向表可以得到以下报表:
Report 1 |
| |||
|
Page 1 |
| ||
姓名 |
电话 |
| ||
李丽 |
22221111 |
| ||
Page 2 |
| |||
机器: HP 520 | ||||
供应商: Verizon |
Report 2 |
| |||
|
Page 1 |
| ||
姓名 |
电话 |
电子邮件 | ||
马军 |
33334444 |
m@mail.com | ||
Page 2 |
| |||
机器: IBM T61 |
总结
本文为大家介绍了在数据库表中存储数据的两种不同方式。虽然纵向数据布局的缺点往往会把它的优点覆盖掉,但某些情况下为了获得灵活性,这种纵向结构是设计数据组织结构的唯一出路。另一方面,横向表则是管理数据库管理系统中存储数据的传统模式,更易于实现数据规范化。对于软件和数据库而言,要选择何种设计方式来长久保存数据取决于特定的应用需求。