【发布时间】:2010-04-23 20:25:44
【问题描述】:
我的理解是,ROWID 是查询返回的结果中每一行的唯一值。
为什么我们需要这个 ROWID? ORACLE 中已经有 ROWNUM。
有人在 SQL 查询中使用过 ROWID 吗?
【问题讨论】:
我的理解是,ROWID 是查询返回的结果中每一行的唯一值。
为什么我们需要这个 ROWID? ORACLE 中已经有 ROWNUM。
有人在 SQL 查询中使用过 ROWID 吗?
【问题讨论】:
ROWID 是行的物理位置。因此,它是定位行的最快方法,甚至比主键查找还要快。所以它在某些类型的事务中很有用,我们选择一些行,存储它们的 ROWID,然后稍后在 where 子句中使用 ROWID 来针对这些相同的行进行 DML。
当我们使用 WHERE CURRENT OF 更新锁定的行时,Oracle SELECT ... FOR UPDATE 语法隐式使用 ROWID。此外,EXCEPTIONS 表(在使用 EXCEPTIONS INTO 子句应用约束时引用)具有 ROW_ID 列。这使我们能够快速识别违反约束的行。
后一个例子指向另一种一般用法:当我们编写一些通用代码并且需要一种存储 UID 的机制而不关心数据类型、复合键等时。
另一方面,ROWNUM 是一个伪列,它标记给定结果集中的一行。它没有永久的意义。
编辑
给定记录的 ROWID 可以在系统的整个生命周期内发生变化,例如通过表重建。此外,如果删除一条记录,则可以为该 ROWID 指定一条新记录。因此,从长远来看,ROWID 不适合用作 UID。但它们足以在事务中使用。
【讨论】:
我现在知道了一个例子。
假设您有没有主键的表。所以这个表可以有重复的行。您将如何删除重复的行但只保留其中一个?
Oracle 提供 ROWID 作为主键的一种替代。您可以编写一个相关类型的嵌套查询[(按行中的所有列分组,并在内部查询中的每个组中取 MIN(ROWID),对于每个组,在外部查询中删除该组中的其他行)]
例子
SQL> select * from employees;
SSN NAME
---------- ----------
1 helen
1 helen
2 helen
2 peter
10 sally
11 null
11 null
12 null
8 rows selected.
SQL> delete from employees where ROWID NOT IN (select min(ROWID) from employees
group by ssn,name);
2 rows deleted.
SQL> select * from employees;
SSN NAME
---------- ----------
1 helen
2 helen
2 peter
10 sally
11 null
12 null
6 rows selected.
【讨论】:
请注意,ROWID 不会在数据库 EXPORT 和 IMPORT 周期中持续存在。 你不应该在你的表中存储 rowid 作为键值。
【讨论】:
ROWID 由以下部分组成(但不一定按此顺序,尽管据我记忆,ROWNUM 部分是 ROWID 的最后一部分):
您可以使用 ROWIDTOCHAR() SQL 函数轻松地将 ROWID 分解为复合字段(OBJID、FILENO、BLOCKNO、ROWNUM),或使用:
SQL> select DBMS_ROWID.ROWID_OBJECT(rowid) "OBJECT",
2 DBMS_ROWID.ROWID_RELATIVE_FNO(rowid) "FILE",
3 DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid) "BLOCK",
4 DBMS_ROWID.ROWID_ROW_NUMBER(rowid) "ROW"
5 from dual
6 /
OBJECT FILE BLOCK ROW
---------- ---------- ---------- ----------
258 1 2082 0
注意字段ROWNUM(或上述查询中的ROW)与您在SELECT查询中使用的SQL伪列ROWNUM不是相同的ROWNUM,它只是动态生成的行的行号在结果集中。
请注意,由于这种实现方式,行、块、范围和段在不破坏 ROWID 的情况下是不可传输的,这会使索引无效。
ROWID 是对行所在块的最直接访问路径,并唯一标识行,因为它对文件中的唯一文件和唯一块以及该块中的唯一行进行编码。
更多信息:
注意:
如果你对 oracle 构建数据库文件和块的方式有一点了解,并且知道一些 C 编程,你可以很容易地制作一个程序来显示由 ROWID 给出的块的内容(一个 8k 或任何块大小在数据库中使用,块从 fileheadersize + BLOCKNO * BLOCK_SIZE 开始。块包含块头,然后(假设表未聚集)rowdir,对于每一行,它给出了每一行在块内的相对偏移量。例如,在 rowdir 内的位置 0 是块内第 0 行的相对偏移量,在 rowdir 内的位置 1 是第 1 行的相对位置,等等。行数本身存储在某处块头(请参阅有关块布局的 orale 文档)。
只要有一点编程知识,并在 oracle 数据库文件中查找有关块的确切布局的文档,您就可以看到行是如何存储在磁盘上的,甚至可以重建行为每一列存储的所有值.每行包含行长和列数的元数据,并且对于每列,指示列的类型和字节大小以及值。 Bytesize 0 表示该列数据为空(或:NULL)。
【讨论】:
ROWID 唯一标识表中的一行。 ROWNUM 为您提供特定查询的结果的行号。两者非常不同,不可互换。
还有 ROW_NUMBER,它是 ROWNUM 的更现代版本,其行为略有不同。查看this article,它解释了差异。
【讨论】:
ROWID 基本上允许您有两行具有完全相同的数据。虽然您通常希望主键比 RowID 更有意义,但这只是一种自动确保行之间唯一性的简单方法。
【讨论】: