41

我的理解是,ROWID 是查询返回的结果中每一行的唯一值。

为什么我们需要这个 ROWID?ORACLE 中已经有ROWNUM。

有人在 SQL 查询中使用过 ROWID 吗?

4

6 回答 6

48

ROWID 是行的物理位置。因此,它是定位行的最快方法,甚至比主键查找还要快。因此,它在某些类型的事务中很有用,我们选择一些行,存储它们的 ROWID,然后稍后在whereDML 的子句中使用 ROWID 针对这些相同的行。

当我们使用 WHERE CURRENT OF 更新锁定的行时,Oracle SELECT ... FOR UPDATE 语法隐式使用 ROWID。此外,EXCEPTIONS 表(在使用 EXCEPTIONS INTO 子句应用约束时引用)具有 ROW_ID 列。这使我们能够快速识别违反约束的行。

后一个示例指向另一种通用用法:当我们编写一些通用代码并且需要一种存储 UID 的机制而不关心数据类型、复合键等时。

另一方面,ROWNUM 是一个伪列,它标记给定结果集中的一行。它没有永久的意义。

编辑

给定记录的 ROWID 可以在系统的生命周期内更改,例如通过表重建。此外,如果删除一条记录,则可以为该 ROWID 指定一条新记录。因此,从长远来看,ROWID 不适合用作 UID。但它们足以在事务中使用。

于 2010-04-23T20:31:05.310 回答
13

我现在知道一个例子。

假设您有没有主键的表。所以这个表可以有重复的行。您将如何删除重复的行但只保留其中一个?

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.
于 2010-04-24T07:57:14.333 回答
6

请注意,ROWID 不会在数据库 EXPORT 和 IMPORT 周期中持续存在。你不应该在你的表中存储一个 rowid 作为键值。

于 2010-04-24T17:23:35.163 回答
4

ROWID 由以下部分组成(但不一定按此顺序,尽管据我记得 ROWNUM 部分是 ROWID 的最后一部分):

  • OBJID 对象的唯一标识符。
  • FILENO 表空间中数据文件的相对编号。
  • BLOCKNO 文件头之后数据文件中的相对块号。
  • ROWNUM 块内的相对行号。

您可以使用 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 是对该行所在的块的最直接访问路径,并且唯一地标识该行,因为它对该文件中的唯一文件和唯一块以及该块中的唯一行进行编码。

更多信息:

请参阅:关于 ROWID 格式的 DBMS 说明

笔记:

如果你对 oracle 构建数据库文件和块的方式有一点了解,并且知道一些 C 编程,你可以很容易地制作一个程序来显示由 ROWID 给出的块的内容(一个 8k 或任何块大小在数据库,从fileheadersize + BLOCKNO * BLOCK_SIZE开始的块。该块包含块头,然后(假设表未聚集)rowdir,对于每一行,它给出了每一行在块内的相对偏移量。例如在 rowdir 内的位置 0 是块内第 0 行的相对偏移量,在 rowdir 内的位置 1 是第 1 行的相对位置,等等。行数本身存储在块头中的某处(请参阅有关块布局的 orale 文档)。

有了一点编程知识并在 oracle 数据库文件中查找块的文档以了解块的确切布局,您就可以看到行是如何存储在磁盘上的,甚至可以重建行为每一列存储的所有值。每行包含行长和列数的元数据,并且对于每列,指示列的类型和字节大小以及值。Bytesize 0 表示列数据为空(或:NULL)。

于 2016-12-06T22:19:09.533 回答
3

ROWID 唯一标识表中的一行。ROWNUM 为您提供特定查询的结果的行号。两者差别很大,不能互换。

还有 ROW_NUMBER,它是 ROWNUM 的更现代版本,行为略有不同。查看这篇解释差异的文章。

于 2010-04-23T20:29:00.007 回答
1

ROWID 基本上允许您有两行具有完全相同的数据。虽然您通常希望主键比 RowID 更有意义,但这只是一种自动确保行之间唯一性的简单方法。

于 2010-04-23T20:29:21.433 回答