我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢!
由于博客中有大量代码,通过页面浏览效果更佳。
本文为个人学习《Expert Oracle Database Architecture Techniques and Solutions for High Performance and Productivity(第四版本》一书过程中的笔记与理解分享,仅用于学习与交流,部分内容参考原书观点并结合>实际经验进行整理。若涉及版权问题,请联系删除或沟通处理。也请大家支持购买原版书籍。
什么是对象表?
想象一下,你平时建表像是用乐高积木一块块拼装(定义各个列),而对象表则是直接使用一个现成的、封装好的乐高模型(自定义类型)来建表。它是一种基于自定义类型(TYPE) 来创建的表,表的“列”实际上就是类型中定义的属性。
简单来说:
- 普通建表:
CREATE TABLE t (x INT, y DATE, z VARCHAR2(25));
— 自己指定每一列。 - 对象表建表:
CREATE TABLE t OF Some_Type;
— 直接用一个现成的类型模板来生成表。
一个生动的例子
让我们通过一个“人”的例子来理解它。
第一步:定义“地址”类型
我们先定义一个“地址”的模板(类型),它包含城市、街道、州和邮编这些属性。
CREATE TYPE address_type AS OBJECT (city VARCHAR2(30),street VARCHAR2(30),state VARCHAR2(2),zip NUMBER
);
第二步:定义“人”类型
接着,我们定义一个“人”的模板。一个人有姓名、生日、家庭地址和工作地址。注意,家庭地址和工作地址本身就是我们刚定义的 address_type
类型。
CREATE TYPE person_type AS OBJECT (name VARCHAR2(30),dob DATE,home_address address_type, -- 嵌套了地址类型work_address address_type -- 再次嵌套地址类型
);
第三步:创建对象表
现在,我们不用费力地列出所有列,直接用一个简单的命令就能创建一张“人”表。
CREATE TABLE people OF person_type;
查看这张表的结构,你会发现它看起来非常整洁,就像类型定义一样:
名称 空? 类型
------------ -- ------------------------
NAME VARCHAR2(30)
DOB DATE
HOME_ADDRESS ADDRESS_TYPE
WORK_ADDRESS ADDRESS_TYPE
第四步:使用对象表
向对象表插入数据时,需要使用类型的“构造函数”来组装数据:
INSERT INTO people VALUES ('Tom','15-mar-1965',address_type('Denver', '123 Main Street', 'Co', 12345), -- 构造家庭地址address_type('Redwood', '1 Oracle Way', 'Ca', 23456) -- 构造工作地址
);
查询数据时,可以像普通列一样访问嵌套类型的属性,语法非常直观:
-- 查询这个人的家庭地址在哪座城市
SELECT name, p.home_address.city FROM people p;NAME HOME_ADDRESS.CITY
---------- ------------------------------
Tom Denver
幕后真相:魔法与代价
虽然对象表用起来很酷,但它的背后并不简单。Oracle 最终仍然是以传统的行和列来存储所有数据。当我们创建对象表时,Oracle 在幕后做了大量工作:
- 添加隐藏列:系统会自动添加一些隐藏列来管理数据,比如
SYS_NC_OID$
(一个16字节的系统生成对象ID)和SYS_NC_ROWINFO$
(一个能返回整行对象的魔法函数)。 - 展开嵌套类型:我们的
ADDRESS_TYPE
被“拍平”了,它的每个属性(city, street, state, zip)都变成了表中一个独立的、名字由系统生成的隐藏列(如SYS_NC00006$
)。这是因为列名必须唯一,而嵌套类型可能被多次使用(比如家庭地址和工作地址)。 - 创建唯一索引:系统会自动在
SYS_NC_OID$
列上创建唯一索引。
这意味着:一张看起来只有 4 列的对象表,在底层可能实际上有 14 个(或更多)物理列。这些魔法操作会带来隐藏的复杂性、额外的索引和意想不到的伪列。
对象表 vs. 关系表 + 对象视图:如何选择?
对象表很强大,但它将物理存储和逻辑模型紧密耦合了。很多时候,一种更灵活、更可控的方法是:使用传统关系表存储数据,然后用对象视图(Object View)提供对象接口。
这样做的好处:
- 完全控制存储:你知道数据具体是如何存储的,可以精细优化。
- 保持关系型访问:你的表仍然是标准的关系表,所有现有的工具、应用程序和报表都能无缝使用它,不受任何影响。
- 享受对象优势:需要通过编程(如PL/SQL)以对象方式操作数据的人,仍然可以通过对象视图来获得清晰、易用的对象接口。
- 避免“魔法”开销:你避免了系统自动生成的隐藏列和索引带来的潜在开销和复杂性。
实现方式示例:
-- 1. 创建传统的关系表,明确每一列
CREATE TABLE people_tab (name VARCHAR2(30) PRIMARY KEY,dob DATE,home_city VARCHAR2(30),home_street VARCHAR2(30),home_state VARCHAR2(2),home_zip NUMBER,work_city VARCHAR2(30),work_street VARCHAR2(30),work_state VARCHAR2(2),work_zip NUMBER
);-- 2. 创建一个对象视图,让它看起来和感觉上就像一个对象表
CREATE VIEW people OF person_type
WITH OBJECT IDENTIFIER (name) -- 指定主键name作为对象标识符
AS
SELECT name, dob,address_type(home_city, home_street, home_state, home_zip) home_address,address_type(work_city, work_street, work_state, work_zip) work_address
FROM people_tab;
现在,你可以像插入对象表一样向视图插入数据(对于复杂的视图,可能需要编写 INSTEAD OF
触发器来处理DML操作),同时底层的数据是以你最熟悉、最可控的关系形式存储的。
总结
- 对象表是一种“语法糖”,它让你能用面向对象的方式定义和操作表,但底层仍然是关系存储。
- 它带来了便利,但也伴随着隐藏的复杂性(自动生成的列、索引)。
- 对象视图是一种更推荐的架构选择。它让你鱼和熊掌兼得:既保留了传统关系存储的简单性和兼容性,又为开发者提供了强大的对象操作接口。
- 除非有强烈理由必须使用对象表作为物理存储,否则关系表 + 对象视图的组合通常能提供更大的灵活性和控制力,是实现对象-关系模型的最佳实践。
------------------作者介绍-----------------------
姓名:黄廷忠
现就职:Oracle中国高级服务团队
曾就职:OceanBase、云和恩墨、东方龙马等
电话、微信、QQ:18081072613
个人博客: (http://www.htz.pw)
CSDN地址: (https://blog.csdn.net/wwwhtzpw)
博客园地址: (https://www.cnblogs.com/www-htz-pw)