我有一个大约有1000行的表.我必须将表中的一列("X")更新为'Y'表示n个ramdom行.为此我可以有以下查询
update xyz set X='Y' when m in (
'SELECT m FROM (SELECT m
FROM xyz
order by dbms_random.value
) RNDM
where rownum < n+1);
Run Code Online (Sandbox Code Playgroud)
是否有另一种有效的方法来编写此查询.该表没有索引.请帮忙?
我会使用ROWID:
UPDATE xyz SET x='Y' WHERE rowid IN (
SELECT r FROM (
SELECT ROWID r FROM xyz ORDER BY dbms_random.value
) RNDM WHERE rownum < n+1
)
Run Code Online (Sandbox Code Playgroud)
我使用ROWID的实际原因不是效率(它仍然会进行全表扫描) - 如果列m不唯一,您的SQL可能不会更新所需的行数.
只有1000行,你不应该真的担心效率(可能有一亿行).如果没有此表中的任何索引,您将无法执行全表扫描以选择随机记录.
[编辑:] "但如果有10万行怎么办"
嗯,这仍然是3个数量级,低于1亿.
我运行了以下内容:
create table xyz as select * from all_objects;
Run Code Online (Sandbox Code Playgroud)
[在我的系统上创建了大约50,000行 - 非索引,就像你的表一样]
UPDATE xyz SET owner='Y' WHERE rowid IN (
SELECT r FROM (
SELECT ROWID r FROM xyz ORDER BY dbms_random.value
) RNDM WHERE rownum < 10000
);
commit;
Run Code Online (Sandbox Code Playgroud)
这花了大约1.5秒.也许是1秒钟,也许是3秒钟(没有正式计时,它只花了足够的时间眨眼).
您可以使用样本替换全表扫描来提高性能.
您遇到的第一个问题是您不能在DML子查询中使用SAMPLE ORA-30560: SAMPLE clause not allowed.但从逻辑上讲,这就是所需要的:
UPDATE xyz SET x='Y' WHERE rowid IN (
SELECT r FROM (
SELECT ROWID r FROM xyz sample(0.15) ORDER BY dbms_random.value
) RNDM WHERE rownum < 100/*n*/+1
);
Run Code Online (Sandbox Code Playgroud)
您可以通过使用集合来存储rowid,然后使用rowid集合更新行来解决此问题.通常将查询分解为单独的部分并将它们与PL/SQL粘合在一起会导致可怕的性能.但在这种情况下,您仍然可以通过显着减少读取的数据量来节省大量时间.
declare
type rowid_nt is table of rowid;
rowids rowid_nt;
begin
--Get the rowids
SELECT r bulk collect into rowids
FROM (
SELECT ROWID r
FROM xyz sample(0.15)
ORDER BY dbms_random.value
) RNDM WHERE rownum < 100/*n*/+1;
--update the table
forall i in 1 .. rowids.count
update xyz set x = 'Y'
where rowid = rowids(i);
end;
/
Run Code Online (Sandbox Code Playgroud)
我运行了一个简单的测试,有100,000行(在一个只有两列的表上),N = 100.原始版本耗时0.85秒,@ Gerrat的答案耗时0.7秒,PL/SQL版本需要0.015秒.
但这只是一种情况,我没有足够的信息说我的回答总会更好.随着N的增加,采样优势会丢失,写入将比读数更重要.如果您的数据量非常少,我的答案中的PL/SQL上下文切换开销可能比@ Gerrat的解决方案慢.
对于性能问题,表的大小(以字节为单位)通常比行中的大小重要得多.使用1 TB空间的1000行远远大于仅使用1 GB的1亿行.
以下是我的答案需要考虑的一些问题:
N更改,您将需要使用动态SQL来更改百分比.| 归档时间: |
|
| 查看次数: |
9032 次 |
| 最近记录: |