這幾天工作上的需要,要從一個比較大的表中隨機取出一條記錄,oracle 不像MS SQLSERVER那樣,直接用Select TOP 1 * From TABLE Order By NewID(),就能高效的隨機查出一條記錄。經過一翻折騰,用一個有90萬條記錄的表t_id,只有一個gameid字段,該字段上沒有索引,表里就是從100000到999999一連串的數據記錄,進行測試:
方法1.
采用rownum和dbms_random.value,平均用時5秒,這個效率確實是太低了,對於小表應該還行,大表那就太不適合了。
declare
n_id number(6);
begin
SELECT gameid into n_id FROM(SELECT gameid FROM t_id T ORDER BY dbms_random.value()) WHERE ROWNUM=1;
dbms_output.put_line(to_char(n_id));
end;
/
方法2.
采用oracle sample語法,設置隨機樣本是1%,結果用時0.01左右,速度是相當快的,但是根據官網的說法,采用sample采集特性可能會產生不准確的結果集,我在測試中是沒有碰到不正確的結果。但是有個問題,就是隨機的結果分布很不平均,結果幾乎都分內存卡在100000-200000的記錄中。效率雖好,但並沒有達到很好的隨機效果,如果對於結果的要求不是很高的,這個方法是相當不錯的。
declare
n_id number(6);
begin
SELECT gameid into n_id FROM t_id SAMPLE (1) WHERE ROWNUM = 1;
dbms_output.put_line(to_char(n_id));
end;
/
方法3.
采用minus語法,先隨機獲取一個在表總記錄數范圍內的一個隨機數,再通過rownum查詢兩個結果集只相差一條記錄,用minus相減留出事先隨機數的那條記錄,平均用時大概1秒,隨機數越小,查詢速度越快,當隨機數是20000時,用於0.016秒。該方法雖然
能得到很有隨機效果,但效率比較不上該方法2. 對效率要求一般的話, 還是可以考慮使用的。
declare
n_count int:=0;
n_rand_num int:=0;
n_id number(6);
begin
SELECT COUNT(*) INTO n_count FROM t_id;
SELECT trunc(dbms_random.value(1,n_count+1)) INTO n_rand_num FROM DUAL;
select gameid into n_id from (SELECT gameid FROM t_id T WHERE rownum<n_rand_num
minus
SELECT gameid FROM t_id T WHERE rownum<n_rand_num-1);
dbms_output.put_line(to_char(n_id));
end;
/
還有別的方法,可以參考下http://www.oracle.com.cn/viewthread.php?tid=130433&extra=page%3D1