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中如何按行号查询的主要内容,如果未能解决你的问题,请参考以下文章