আপনার স্পেসিফিকেশন দেওয়া হয়েছে (অতিরিক্ত মন্তব্যগুলিতে অতিরিক্ত তথ্য),
- আপনার কাছে কয়েকটি সংখ্যক (বা মাঝারিভাবে কয়েকটি) ফাঁক দিয়ে একটি সংখ্যামূলক আইডি কলাম (পূর্ণসংখ্যা সংখ্যা) রয়েছে।
- স্পষ্টতই কোনও বা কয়েকটি লেখার কাজ নেই।
- আপনার আইডি কলামটি ইনডেক্স করতে হবে! একটি প্রাথমিক কী দুর্দান্তভাবে পরিবেশন করে।
নীচের ক্যোয়ারিতে বড় টেবিলের ক্রমিক স্ক্যানের প্রয়োজন নেই, কেবল একটি সূচক স্ক্যান।
প্রথমে মূল ক্যোয়ারির জন্য অনুমানগুলি পান:
SELECT count(*) AS ct -- optional
, min(id) AS min_id
, max(id) AS max_id
, max(id) - min(id) AS id_span
FROM big;
কেবলমাত্র ব্যয়বহুল অংশটি হ'ল count(*)
(বিশাল টেবিলগুলির জন্য)। উপরের বৈশিষ্ট্যগুলি দেওয়া, আপনার এটির দরকার নেই। একটি অনুমান কেবল জরিমানা করবে, প্রায় কোনও ব্যয় ছাড়াই উপলব্ধ ( বিস্তারিত বিশদ এখানে ):
SELECT reltuples AS ct FROM pg_class WHERE oid = 'schema_name.big'::regclass;
যতক্ষণ ct
না এর চেয়ে বেশি ছোট নয় id_span
, ক্যোয়ারী অন্যান্য পদ্ধতির চেয়ে বেশি কার্যকর হবে।
WITH params AS (
SELECT 1 AS min_id -- minimum id <= current min id
, 5100000 AS id_span -- rounded up. (max_id - min_id + buffer)
)
SELECT *
FROM (
SELECT p.min_id + trunc(random() * p.id_span)::integer AS id
FROM params p
,generate_series(1, 1100) g -- 1000 + buffer
GROUP BY 1 -- trim duplicates
) r
JOIN big USING (id)
LIMIT 1000; -- trim surplus
id
স্পেসে এলোমেলো সংখ্যা তৈরি করুন । আপনার "কয়েকটি ফাঁক" রয়েছে, তাই পুনরুদ্ধার করার জন্য 10% (সহজেই ফাঁকা অংশগুলি coverাকতে যথেষ্ট) যোগ করুন।
প্রতিটি একযোগে id
একাধিকবার বাছাই করা যায় (যদিও একটি বড় আইডি স্পেসের সাথে খুব সম্ভবত) তবে উত্পন্ন সংখ্যাগুলি (বা ব্যবহার করুন DISTINCT
) গ্রুপ করুন ।
id
বড় টেবিলে এস যোগ দিন । জায়গাটি সূচকের সাথে এটি খুব দ্রুত হওয়া উচিত।
অবশেষে ছাঁটাই উদ্বৃত্ত id
গুলি যেগুলি ডুপ এবং ফাঁক দ্বারা খাওয়া হয়নি। প্রতিটি সারিতে বাছাই করার সম্পূর্ণ সমান সুযোগ রয়েছে ।
সংক্ষিপ্ত সংস্করণ
আপনি এই ক্যোয়ারী সরল করতে পারেন । উপরের ক্যোয়ারিতে থাকা সিটিই কেবলমাত্র শিক্ষামূলক উদ্দেশ্যে:
SELECT *
FROM (
SELECT DISTINCT 1 + trunc(random() * 5100000)::integer AS id
FROM generate_series(1, 1100) g
) r
JOIN big USING (id)
LIMIT 1000;
আরসিটিই দিয়ে পরিমার্জন করুন
বিশেষ করে যদি আপনি ফাঁক এবং অনুমান সম্পর্কে নিশ্চিত না হন।
WITH RECURSIVE random_pick AS (
SELECT *
FROM (
SELECT 1 + trunc(random() * 5100000)::int AS id
FROM generate_series(1, 1030) -- 1000 + few percent - adapt to your needs
LIMIT 1030 -- hint for query planner
) r
JOIN big b USING (id) -- eliminate miss
UNION -- eliminate dupe
SELECT b.*
FROM (
SELECT 1 + trunc(random() * 5100000)::int AS id
FROM random_pick r -- plus 3 percent - adapt to your needs
LIMIT 999 -- less than 1000, hint for query planner
) r
JOIN big b USING (id) -- eliminate miss
)
SELECT *
FROM random_pick
LIMIT 1000; -- actual limit
বেস কোয়েরিতে আমরা একটি ছোট উদ্বৃত্ত নিয়ে কাজ করতে পারি । যদি অনেকগুলি শূন্যস্থান থাকে তাই আমরা প্রথম পুনরাবৃত্তিতে পর্যাপ্ত সারি খুঁজে পাই না, আরসিটিই পুনরাবৃত্তির শব্দটি দিয়ে পুনরাবৃত্তি করতে থাকে। আমাদের এখনও আইডি স্পেসে তুলনামূলকভাবে কয়েকটি ফাঁক প্রয়োজন বা সীমাটি পৌঁছানোর আগেই পুনরাবৃত্তি শুকিয়ে যেতে পারে - বা আমাদের একটি বৃহত যথেষ্ট বাফার দিয়ে শুরু করতে হবে যা পারফরম্যান্স অনুকূলকরণের উদ্দেশ্যকে অস্বীকার করে।
UNION
অনুলিপিগুলি আরসিটিই- এর মাধ্যমে মুছে ফেলা হয় ।
বাইরের LIMIT
যত তাড়াতাড়ি আমরা পর্যাপ্ত সারি আছে কোটে স্টপ করে তোলে।
এই ক্যোয়ারীটি সাবধানতার সাথে উপলভ্য সূচীটি ব্যবহার করতে, আসলে এলোমেলো সারি তৈরি করতে এবং সীমাটি সীমাবদ্ধ না করা অবধি থামানো হবে না (যদি না পুনরাবৃত্তিটি শুকিয়ে না যায়)। আপনি যদি এটি আবার লিখতে চলেছেন তবে এখানে বেশ কয়েকটি সমস্যা রয়েছে।
ফাংশন মোড়ানো
বিভিন্ন পরামিতিগুলির সাথে পুনরাবৃত্তি ব্যবহারের জন্য:
CREATE OR REPLACE FUNCTION f_random_sample(_limit int = 1000, _gaps real = 1.03)
RETURNS SETOF big AS
$func$
DECLARE
_surplus int := _limit * _gaps;
_estimate int := ( -- get current estimate from system
SELECT c.reltuples * _gaps
FROM pg_class c
WHERE c.oid = 'big'::regclass);
BEGIN
RETURN QUERY
WITH RECURSIVE random_pick AS (
SELECT *
FROM (
SELECT 1 + trunc(random() * _estimate)::int
FROM generate_series(1, _surplus) g
LIMIT _surplus -- hint for query planner
) r (id)
JOIN big USING (id) -- eliminate misses
UNION -- eliminate dupes
SELECT *
FROM (
SELECT 1 + trunc(random() * _estimate)::int
FROM random_pick -- just to make it recursive
LIMIT _limit -- hint for query planner
) r (id)
JOIN big USING (id) -- eliminate misses
)
SELECT *
FROM random_pick
LIMIT _limit;
END
$func$ LANGUAGE plpgsql VOLATILE ROWS 1000;
কল করুন:
SELECT * FROM f_random_sample();
SELECT * FROM f_random_sample(500, 1.05);
আপনি যেকোন টেবিলের জন্য কাজ করার জন্য এই জেনেরিকটি তৈরি করতে পারেন: পিকে কলামের নাম এবং টেবিলটিকে পলিমারফিক টাইপ এবং ব্যবহার হিসাবে গ্রহণ করুন EXECUTE
... তবে এটি এই প্রশ্নের ক্ষেত্রের বাইরে beyond দেখা:
সম্ভাব্য বিকল্প
যদি আপনার প্রয়োজনীয়তাগুলি বারবার কলগুলির জন্য অভিন্ন সেটগুলি মঞ্জুরি দেয় (এবং আমরা বারবার কল করার বিষয়ে কথা বলছি) তবে আমি একটি বস্তুগত দৃষ্টিভঙ্গি বিবেচনা করব । উপরের প্রশ্নগুলি একবার কার্যকর করুন এবং ফলাফলটি একটি টেবিলে লিখুন। ব্যবহারকারীরা বিদ্যুত গতিতে একটি পরিমাণের এলোমেলো নির্বাচন পান। আপনার পছন্দমতো বিরতি বা ইভেন্টগুলিতে আপনার এলোমেলো বাছুনিকে রিফ্রেশ করুন।
যেখানে n
এক শতাংশ। ম্যানুয়াল:
BERNOULLI
এবং SYSTEM
স্যাম্পলিং পদ্ধতি প্রতিটি একটি একক যুক্তি যা নমুনা টেবিলের ভগ্নাংশ, একটি হিসাবে প্রকাশ করা হয় গ্রহণ
0 এবং 100 এর মধ্যে শতকরা । এই যুক্তিটি যে কোনও real
মূল্যায়িত অভিব্যক্তি হতে পারে ।
বোল্ড জোর আমার। এটি খুব দ্রুত , তবে ফলাফলটি এলোমেলো নয় । ম্যানুয়াল আবার:
SYSTEM
পদ্ধতি উল্লেখযোগ্যভাবে দ্রুততর চেয়ে BERNOULLI
পদ্ধতি যখন ছোট স্যাম্পলিং শতকরা নিদিষ্ট করা হয়, কিন্তু এটিকে প্রভাব ক্লাস্টারিং ফলে টেবিলের একটি কম-র্যান্ডম নমুনা ফেরত দিতে পারেন।
ফিরে আসা সারির সংখ্যা হিংস্রভাবে পরিবর্তিত হতে পারে। আমাদের উদাহরণস্বরূপ, প্রায় 1000 সারি পেতে :
SELECT * FROM big TABLESAMPLE SYSTEM ((1000 * 100) / 5100000.0);
সম্পর্কিত:
অথবা অনুরোধকৃত সারিগুলির সংখ্যা পেতে (অতিরিক্ত পর্যায়ে থাকলে) অতিরিক্ত মডিউল টিএসএম_সিস্টেম_সগুলি ইনস্টল করুন এবং আরও সুবিধাজনক সিনট্যাক্সের জন্য অনুমতি দিন:
SELECT * FROM big TABLESAMPLE SYSTEM_ROWS(1000);
বিস্তারিত জানার জন্য ইভানের উত্তর দেখুন ।
তবে এটি এখনও ঠিক এলোমেলো নয়।