मैं बिना किसी बहुत तेजी से समाधान के साथ आया हूं TABLESAMPLE। से बहुत तेज OFFSET random()*N LIMIT 1। इसके लिए टेबल काउंट की भी आवश्यकता नहीं होती है।
उदाहरण के लिए, यादृच्छिक लेकिन पूर्वानुमानित डेटा के साथ एक अभिव्यक्ति सूचकांक बनाने का विचार है md5(primary key)।
यहाँ 1M पंक्तियों के नमूने का परीक्षण किया गया है:
create table randtest (id serial primary key, data int not null);
insert into randtest (data) select (random()*1000000)::int from generate_series(1,1000000);
create index randtest_md5_id_idx on randtest (md5(id::text));
explain analyze
select * from randtest where md5(id::text)>md5(random()::text)
order by md5(id::text) limit 1;
परिणाम:
Limit (cost=0.42..0.68 rows=1 width=8) (actual time=6.219..6.220 rows=1 loops=1)
-> Index Scan using randtest_md5_id_idx on randtest (cost=0.42..84040.42 rows=333333 width=8) (actual time=6.217..6.217 rows=1 loops=1)
Filter: (md5((id)::text) > md5((random())::text))
Rows Removed by Filter: 1831
Total runtime: 6.245 ms
यह क्वेरी कभी-कभी (लगभग 1 / Number_of_rows संभावना के साथ) 0 पंक्तियाँ लौटाती है, इसलिए इसे जाँचने और पुन: चलाने की आवश्यकता होती है। इसके अलावा संभाव्यताएं समान नहीं हैं - कुछ पंक्तियाँ दूसरों की तुलना में अधिक संभावित हैं।
तुलना के लिए:
explain analyze SELECT id FROM randtest OFFSET random()*1000000 LIMIT 1;
परिणाम व्यापक रूप से भिन्न होते हैं, लेकिन बहुत खराब हो सकते हैं:
Limit (cost=1442.50..1442.51 rows=1 width=4) (actual time=179.183..179.184 rows=1 loops=1)
-> Seq Scan on randtest (cost=0.00..14425.00 rows=1000000 width=4) (actual time=0.016..134.835 rows=915702 loops=1)
Total runtime: 179.211 ms
(3 rows)