在本文中,我将分析(关系)数据库中组织数据的不同方式,在本文的例子中,我采用Oracle进行阐述,但其他关系数据库面临同样的问题,这些关系数据库组织数据的方式既有优点也有缺点,将给以区分,据此读者可判定适合他们的需要数据组织方式。
采用何种数据组织方式,取决于业务需求和开发需要,各种存储数据的方式可以实现。第一种组织数据的方式是横向结构,这是传统的数据存储方式,每一新的数据记录插入为一行,表中的列横向组织(布局),正如其名。第二种组织数据的方式为纵向结构,这是纵向存储数据的特定方式,表中仅包含两个实际数据列,其中之一用于标识行(但可有更多的列),数据以键/值对(key/value pair)方式存储,亦如其名。
纵向结构与横向结构的比较
下面是传统的横向表结构的例子:
表 HR
ID | First_Name | Last_Name | Dept | Sex |
123 | Vlad | Kofman | IT | M |
234 | Jim | Cramer | Marketing | M |
456 | Olimpia | Dukakis | Accounting | F |
下表为纵向表结构的例子:
表 VR
ID | Key | Value |
123 | First_Name | Vlad |
234 | First_Name | Jim |
456 | First_Name | Olimpia |
123 | Last_Name | Kofman |
234 | Last_Name | Cramer |
456 | Last_Name | Dukakis |
123 | Dept | IT |
234 | Dept | Marketing |
456 | Dept | Accounting |
123 | Sex | M |
234 | Sex | M |
456 | Sex | F |
正如所见,数据从 3行 x 4列 的矩阵(表HR)转换为 12行 x 2列 的矩阵(表VR),好像纵向表的行数等于横向表的记录数乘以横向表的列数,例如 3x4=12。然而,这种假设并不正确,将在下文中讨论该问题。
纵向数据存储的优点和缺点
基于预知的结构和列,以传统的横向结构存储数据具有很多优点,但也存在缺点。加入有一应用表单,其表单完全是动态的,无具体的字段数量和名称,用户可能随时创建一新的字段,并给定其名称和值,如何将其持久化到数据库中呢?
先假设另一不同的场景,其中表单基于业务需求创建,包含一些特定业务要求的字段,每一表单的数据存储在横向表中,其中每一字段插入一特定的列,每一表单存储为一行,一月后,应用上线,业务需要一新的字段,在表单中加入新的字段,UI及其存储逻辑需要调整,实际数据表也需要额外加入字段,应用也需要重新测试和部署。
I在开发人员无权直接访问数据库的环境中,DBA要直接介入更改实际表(结构)。
那么,若一月后需增加另一字段将如何呢?
上述两种应用场景,纵向数据结构可应用于差异的动态应用逻辑层及UI。由于数据仅以Key/Value对的两列存储,通过唯一的id与逻辑表单关联,对表单中字段的数量无限制;此外,纵向表结构下,一逻辑行可含有不同数量的字段,因此,纵向表结构的最大优点就是其可扩展性,但也存在很多缺点。
(葱香结构表)具备了可扩展性,但失去了对数据的可控性,意味着正常数据极难维护。不属于单表的逻辑行可能存储在一起,例如,纵向结构表中的Mutual Fund信息可与分析师名称和合同信息混合,而正常情况下此类信息应该存储在另外的表中,而以其外键id与Fund关联。
纵向结构表中也缺失数据类型。因为列值仅有一类(例如 varchar),所有列值不仅需要类型,且在存储和检索时需要类型转换,且在纵向结构表中不可能存储特殊数据类型,诸如 Blob 或 Clob。
纵向结构表的另一缺点是数据的一致性。事实上,所有列名作为Key列的数据,利于用户(或应用)存储不同的名为key的可能的标识数据。例如,某用户可创建一新字段将其值“Oracle”作为“Company”存储,但另一用户可将“Oracle”作为“Organization”。
此外,操纵及应用纵向结构表也非常困难。为找到所需的逻辑行,需要许多自连接(self-join),因此,只有极少数的商业报表系统可工作于纵向表结构下并生成各类有意义的报表。
例如:从横向表中获取所有男性人员,select语句如下:
Select * from HR where sex like 'M'
要从纵向表中获取同样的数据,需要自连接(self-join),先获取id(集合),然后获取数据:
Select * from VR where id in
(Select id from VR
where key = 'sex'
and value = 'M')
许多开发人员,编写特定的数据库函数或存储过程来讲纵向结构的数据转换为横向结构的数据,以便易于获取报表或其它工作所需的数据。
纵向数据存储结构的变种为包含用于聚合逻辑数据行的定制算法,其含义为可用更多的ID列作为分组(group)属性,例如:
ID | Grouping | KEY | VALUE |
123 | 1 | name | Vlad |
123 | 1 | phone | 555-555-5555 |
123 | 2 | machine | Dell 560 |
123 | 2 | ISP | Verizon |
234 | 1 | name | Mariya |
234 | 1 | phone | 555-456-8392 |
234 | 1 | m@mail.com | |
243 | 2 | machine | Dell 1750 |
报表生成后,可轻易地基于“grouping”列分成不同的页面(page)或片段(section)。因此,上述纵向表可变成如下报表:
Report 1 | ||||
Page 1 | ||||
Name | Phone | |||
Vlad | 555-555-5555 | |||
Page 2 | ||||
Machine: Dell 560 | ||||
ISP: Verizon |
Report 2 | ||||
Page 1 | ||||
Name | Phone | Email | ||
Mariya | 555-456-8392 | m@mail.com | ||
Page 2 | ||||
Machine: Dell 1750 |
可注意到不同形式的报表和页面其中数据的数目各不相同。
结论
上文中,揭示了在数据库表中持久化数据的不同方式,纵向结构所具有的优势和扩展性常被其短处掩蔽。然其可扩展性,通常是设计数据结构的仅有方法。此外,横向结构表可很好适用于正常的数据,也是关系数据库系统持久化数据的传统方式。软件及其数据库架构师对于特定的应用需求将决定采用何种数据库表的设计方式。