oracle中如何按行号查询

Posted

技术标签:

【中文标题】oracle中如何按行号查询【英文标题】:how to query by row number in oracle 【发布时间】:2016-03-28 20:04:14 【问题描述】:

有没有办法直接在Oracle中的表中按行号查询?换句话说,用一些基本的语言,如 C 或 Java,实现与在数组中进行普通查找相同的效果。我还没有尝试过虚拟列。

例如,下面是一个高效查询的示例,但它会浪费磁盘空间:

create table ary (row_position_id number(10) NOT NULL,
                  datum binary_float NOT NULL);
declare i pls_integer;
begin
    for i in 0..10000000
    loop
        insert into ary values (i, dbms_random.normal());
    end loop;
    commit;
end;

create unique index ary_rp on ary(row_position_id);

现在,我将创建一组查询值以存储在另一个“参数”表中:

create table query_values (qval number(10) NOT NULL);
declare i pls_integer;
begin
    for i in 0..10000
    loop
        insert into query_values (abs(dbms_random.random() % 10000000));
    end loop;
    commit;
end;

现在,有了这些查询值,我将查询原始表

select d.* from ary d where exists (select 0 from query_values v
                                    where d.row_position_id = v.qval);

现在,这个查询就可以了——它将使用 INDEX UNIQUE SCAN 和 ROWID 的 TABLE 访问。我遇到的问题是 row_position_id 在表块中占用的空间与实际数据(DATUM 列)一样多。

我知道索引组织表和虚拟列(不能与 IOT 一起使用)。当然,像 ROWNUM 和 ROW_NUMBER 这样的东西在这里是无关紧要的(除非我误解了什么)。

另外值得指出的是,这个表是静态数据——一旦加载,它就永远不会改变。我可能会做一个 ALTER TABLE ARY READ ONLY;

我真正想要的是:

create table ary (datum binary_float not null);
-- load rows in a specific order
-- efficiently query this table by implicit row position

非常感谢!

亨利

【问题讨论】:

【参考方案1】:

我认为您会想要保留额外的列。原因如下:

如您所说,ROWNUM 和 ROW_NUMBER 在这里不适用,因为它们是在查询中返回行时生成的;他们不会告诉您有关插入顺序的任何信息。

ROWID 呢? ROWID 只是存储行的位置 - 再次来自docs:

对象的数据对象编号 行所在的数据文件中的数据块 行在数据块中的位置(第一行为0) 行所在的数据文件(第一个文件是 1)。文件编号是相对于表空间的。

“数据块中的位置”听起来很有趣,但是您不知道插入的数据块的顺序(Oracle 可以使用它可以快速使用的任何数据块),因此这不是一个可靠的选择,即使如此,您也必须解析人类不可读的 ROWID(例如,在 12g 中,它们看起来像这样:*BAGAASMCwQL+)

另一个选项是 ORA_ROWSCN,它的有趣之处在于它确实让您对系统更改编号方面的顺序有所了解。但是,它不是免费的。刚开始,您必须使用 ROWDEPENDENCIES 选项并按照docs 创建表:

ROWDEPENDENCIES 如果要启用,请指定 ROWDEPENDENCIES 行级依赖跟踪。此设置主要用于 允许在复制环境中并行传播。 将每行的大小增加 6 个字节

另一个问题是,您必须在插入的每一行之后添加一个提交,这样每一行都会获得不同的 SCN。

如果您愿意走这么远,您仍然需要将行转换为具有可用于连接到其他表的索引(例如,从 0 或 1 开始)。

以下是它所涉及的快速示例:

DROP TABLE temp;

CREATE TABLE temp 
   ( a number(10)
   , b varchar2(10)
   ) 
ROWDEPENDENCIES
;

-- one commit after all rows    
INSERT INTO temp VALUES (1, 'A');
INSERT INTO temp VALUES (2, 'B');
INSERT INTO temp VALUES (3, 'C');
INSERT INTO temp VALUES (4, 'D');
INSERT INTO temp VALUES (5, 'E');
INSERT INTO temp VALUES (6, 'F');
COMMIT;

SELECT X.*, ROWNUM
FROM (SELECT T.*
           , ORA_ROWSCN
        FROM TEMP T
       ORDER BY ORA_ROWSCN
     ) x
;    

A   B   ORA_ROWSCN  ROWNUM
1   A   2272340          1
2   B   2272340          2
6   F   2272340          3
4   D   2272340          4
5   E   2272340          5
3   C   2272340          6

哎呀。这些行绝对不是它们进入的顺序。

现在每行使用一个提交:

TRUNCATE TABLE temp;

INSERT INTO temp VALUES (1, 'A');
COMMIT;
INSERT INTO TEMP VALUES (2, 'B');
COMMIT;
INSERT INTO temp VALUES (3, 'C');
COMMIT;
INSERT INTO temp VALUES (4, 'D');
COMMIT;
INSERT INTO temp VALUES (5, 'E');
COMMIT;
INSERT INTO temp VALUES (6, 'F');
COMMIT;

SELECT X.*, ROWNUM
FROM (SELECT T.*
           , ORA_ROWSCN
        FROM TEMP T
       ORDER BY ORA_ROWSCN
     ) x
;

A   B   ORA_ROWSCN  ROWNUM
1   A   2272697          1
2   B   2272699          2
3   C   2272701          3
4   D   2272703          4
5   E   2272705          5
6   F   2272707          6

更好。但是如果你有大量的行,它就不会很快进入。 (如果您有意减慢您的插入速度,我认为您会这样做。;)

我认为这与您尝试使用自己的列一样好,但仍有希望节省存储空间:您可以取消表 + 索引,而只使用索引组织的表.它基本上是您直接查询的索引。

就是这么简单:

CREATE TABLE TEMP2
( A NUMBER(10)
, B VARCHAR2(10)
, CONSTRAINT PK_CONSTRAINT PRIMARY KEY (A)
)
ORGANIZATION INDEX 
;

您还需要为此考虑其他参数,但要了解更多信息,请查看...docs。

【讨论】:

谢谢帕特里克。我担心这就是答案;)我已经对索引组织表进行了很多实验,虽然它们在这种情况下表现更好(我认为适合这个用例),但它们仍然相去甚远我认为最有效的解决方案。我不认为您已经尝试过巧妙地使用 LOB 和 PL/SQL 来表示相同的信息? 除非你想引入上下文切换,否则我会远离 PL/SQL。 (我刚刚阅读了一篇文章,其中 12c 允许在 WITH 子句中嵌入 PL/SQL - oracle.com/technetwork/issue-archive/2013/13-sep/… - 并且显然绕过了上下文切换,但根据这里的标签,你使用的是 11g,所以你会付出代价。 ) 如果物联网适用于这种情况,那么您想用 LOB 之类的东西解决一般情况是什么? 我会尝试 lob 解决方案。我应该解释一下,我实际上想要一个 2d 数组,而不是 1d。 (1d 将是获取 2d 数组的通用技术,但如果我不能直接拥有,那么可能是一个 lob 表,每个表示数组中的一行。顺便说一句,我发现 pl/sql 真的很高效。你只需要使用批量 sql 和并行流水线表函数,并且上下文切换最少。

以上是关于oracle中如何按行号查询的主要内容,如果未能解决你的问题,请参考以下文章

Oracle的查询-分页查询

mysql带行号查询

oracle我如何在过程/包中找到开始的行号

在 MS Access 上返回行号

VBA中如何取得行号和列号如何选定这一范围的值

如何从文件中读取特定行(按行号)?