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