আমি ছাড়া খুব দ্রুত সমাধান নিয়ে এসেছি 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 / সংখ্যা_আফ_আর সম্ভাব্যতার সাথে) 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)