【问题标题】:how to query by row number in oracleoracle中如何按行号查询
【发布时间】: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

非常感谢!

亨利

【问题讨论】:

    标签: oracle11g query-optimization


    【解决方案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 和并行流水线表函数,并且上下文切换最少。
    猜你喜欢
    • 2014-05-27
    • 1970-01-01
    • 1970-01-01
    • 2011-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多