读书笔记:什么是对象表?

我们的文章会在微信公众号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)提供对象接口

这样做的好处:

  1. 完全控制存储:你知道数据具体是如何存储的,可以精细优化。
  2. 保持关系型访问:你的表仍然是标准的关系表,所有现有的工具、应用程序和报表都能无缝使用它,不受任何影响。
  3. 享受对象优势:需要通过编程(如PL/SQL)以对象方式操作数据的人,仍然可以通过对象视图来获得清晰、易用的对象接口。
  4. 避免“魔法”开销:你避免了系统自动生成的隐藏列和索引带来的潜在开销和复杂性。

实现方式示例:

-- 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)

posted @ 2025-09-09 17:09  认真就输  阅读(9)  评论(0)    收藏  举报