এলোমেলো সারি PostgreSQL নির্বাচন করার সর্বোত্তম উপায়


345

আমি পোস্টগ্রেএসকিউএল এ সারিগুলির একটি এলোমেলো নির্বাচন চাই, আমি এটি চেষ্টা করেছি:

select * from table where random() < 0.01;

তবে কিছু অন্যরা এটির সুপারিশ করে:

select * from table order by random() limit 1000;

আমার 500 মিলিয়ন সারিগুলির একটি খুব বড় টেবিল রয়েছে, আমি চাই এটি দ্রুত হোক।

কোন পদ্ধতির ভাল? পার্থক্য কি? এলোমেলো সারি নির্বাচন করার সর্বোত্তম উপায় কী?


1
হাই জ্যাক, আপনার প্রতিক্রিয়াটির জন্য ধন্যবাদ, মৃত্যুদন্ড কার্যকর করার সময়টি ধীরে ধীরে, তবে আমি জানতে চাই কোনটি আলাদা কিনা ...
nanounanue

আহ্ ... আপনাকে স্বাগতম সুতরাং, আপনি কি বিভিন্ন পদ্ধতির বেঞ্চমার্ক চেষ্টা করেছেন?

এছাড়াও রয়েছে অনেক দ্রুততর উপায়ে। এটি সমস্ত আপনার প্রয়োজনীয়তা এবং আপনাকে কী কাজ করতে হবে তার উপর নির্ভর করে। আপনার কি ঠিক 1000 সারি দরকার? টেবিলের একটি সংখ্যা আইডি আছে? না / কয়েক / অনেক ফাঁক দিয়ে? গতি কতটা গুরুত্বপূর্ণ? টাইম ইউনিটে কত অনুরোধ? প্রতিটি অনুরোধের জন্য কি আলাদা সেট দরকার হয় বা নির্ধারিত সময়ের জন্য তারা কী একই হতে পারে?
এরউইন ব্র্যান্ডসটেটার

6
"(এলোমেলো () <0.01)" প্রথম বিকল্পটি গাণিতিকভাবে ভুল কারণ আপনি যদি কোনও র্যান্ডম সংখ্যা 0.01 এর নীচে না পান তবে প্রতিক্রিয়াতে কোনও সারি পাওয়া যাবে না, এটি কোনও ক্ষেত্রেই ঘটতে পারে (কম সম্ভাবনা সত্ত্বেও), টেবিলটি যত বড়ই হোক না কেন you বা প্রান্তিকতর উচ্চতর। দ্বিতীয় বিকল্পটি সর্বদা সঠিক
হার্মে

1
আপনি যদি কেবল একটি সারি নির্বাচন করতে চান তবে এই প্রশ্নটি দেখুন: stackoverflow.com/q/5297396/247696
ফ্লিম

উত্তর:


230

আপনার স্পেসিফিকেশন দেওয়া হয়েছে (অতিরিক্ত মন্তব্যগুলিতে অতিরিক্ত তথ্য),

  • আপনার কাছে কয়েকটি সংখ্যক (বা মাঝারিভাবে কয়েকটি) ফাঁক দিয়ে একটি সংখ্যামূলক আইডি কলাম (পূর্ণসংখ্যা সংখ্যা) রয়েছে।
  • স্পষ্টতই কোনও বা কয়েকটি লেখার কাজ নেই।
  • আপনার আইডি কলামটি ইনডেক্স করতে হবে! একটি প্রাথমিক কী দুর্দান্তভাবে পরিবেশন করে।

নীচের ক্যোয়ারিতে বড় টেবিলের ক্রমিক স্ক্যানের প্রয়োজন নেই, কেবল একটি সূচক স্ক্যান।

প্রথমে মূল ক্যোয়ারির জন্য অনুমানগুলি পান:

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 দেখা:

সম্ভাব্য বিকল্প

যদি আপনার প্রয়োজনীয়তাগুলি বারবার কলগুলির জন্য অভিন্ন সেটগুলি মঞ্জুরি দেয় (এবং আমরা বারবার কল করার বিষয়ে কথা বলছি) তবে আমি একটি বস্তুগত দৃষ্টিভঙ্গি বিবেচনা করব । উপরের প্রশ্নগুলি একবার কার্যকর করুন এবং ফলাফলটি একটি টেবিলে লিখুন। ব্যবহারকারীরা বিদ্যুত গতিতে একটি পরিমাণের এলোমেলো নির্বাচন পান। আপনার পছন্দমতো বিরতি বা ইভেন্টগুলিতে আপনার এলোমেলো বাছুনিকে রিফ্রেশ করুন।

Postgres 9.5 পরিচয় করিয়ে দেয় TABLESAMPLE SYSTEM (n)

যেখানে 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);

বিস্তারিত জানার জন্য ইভানের উত্তর দেখুন ।

তবে এটি এখনও ঠিক এলোমেলো নয়।


টি টেবিল কোথায় সংজ্ঞায়িত করা হয় ? এটি টি এর পরিবর্তে আর করা উচিত ?
লুক এম

1
@ লুকম: এটি এখানে সংজ্ঞায়িত:, JOIN bigtbl tযা এর জন্য সংক্ষিপ্ত JOIN bigtbl AS ttএকটি হল টেবিল ওরফে জন্য bigtbl। এর উদ্দেশ্য বাক্য সংক্ষিপ্তকরণ করা তবে এটি বিশেষ ক্ষেত্রে এটিটির প্রয়োজন হবে না। আমি আমার উত্তরে ক্যোয়ারীটি সরল করেছিলাম এবং একটি সাধারণ সংস্করণ যুক্ত করেছি।
এরউইন ব্র্যান্ডসেটেটার

জেনারেট_সরিজ (1,1100) থেকে মানগুলির পরিসীমাটির উদ্দেশ্য কী?
o

@ অসাধারণ- ও: লক্ষ্যটি হল 1000 সারি পুনরুদ্ধার করা, আমি কয়েক ফাঁক বা (সম্ভাব্য তবে সম্ভব) ডুপ্লিকেট এলোমেলো সংখ্যার জন্য ক্ষতিপূরণ দেওয়ার জন্য অতিরিক্ত 10% দিয়ে শুরু করি ... ব্যাখ্যাটি আমার উত্তরে।
এরউইন ব্র্যান্ডস্টেটার

এরউইন, আমি আপনার "সম্ভাব্য বিকল্প" এর একটি প্রকরণ পোস্ট করেছি: stackoverflow.com/a/23634212/430128 । আপনার চিন্তা আগ্রহী হবে।
রমন

100

আপনি উভয়ের ব্যবহারের প্রয়োগের পরীক্ষাটি পরীক্ষা করতে এবং তুলনা করতে পারেন

EXPLAIN select * from table where random() < 0.01;
EXPLAIN select * from table order by random() limit 1000;

একটি বড় টেবিলে একটি দ্রুত পরীক্ষা 1 দেখায় যে ORDER BYপ্রথমটি সম্পূর্ণ টেবিলটি সাজায় এবং তারপরে প্রথম 1000 টি আইটেম বাছাই করে। একটি বড় টেবিল বাছাই করা কেবল সেই টেবিলটিই পড়ে না তবে অস্থায়ী ফাইলগুলি পড়া এবং লেখার সাথেও জড়িত। where random() < 0.1শুধুমাত্র একবার সম্পূর্ণ টেবিল স্ক্যান করা হবে।

বড় টেবিলগুলির জন্য এটি আপনি যা চান তা নাও পারে এমনকি একটি সম্পূর্ণ টেবিল স্ক্যানও বেশি সময় নিতে পারে।

একটি তৃতীয় প্রস্তাব হবে

select * from table where random() < 0.01 limit 1000;

এটির সাথে সাথে 1000 টি সারি পাওয়া যাওয়ার সাথে সাথে টেবিল স্ক্যানটি থামিয়ে দেয় এবং তাই শীঘ্রই ফিরে আসে returns অবশ্যই এই র্যান্ডমনেসটি কিছুটা কমিয়ে দেয়, তবে সম্ভবত এটি আপনার ক্ষেত্রে যথেষ্ট ভাল।

সম্পাদনা করুন: এই বিবেচনাগুলি ছাড়াও, আপনি এর জন্য ইতিমধ্যে জিজ্ঞাসা করা প্রশ্নগুলি পরীক্ষা করে দেখতে পারেন। ক্যোয়ারী ব্যবহার করা [postgresql] randomবেশ কয়েকটি হিট দেয়।

এবং আরও কয়েকটি পদ্ধতির রূপরেখার Depez এর একটি লিঙ্কযুক্ত নিবন্ধ:


1 "বৃহত্তর" হিসাবে "সম্পূর্ণ টেবিলটি মেমরির সাথে খাপ খায় না"।


1
অর্ডার করার জন্য অস্থায়ী ফাইলটি লেখার বিষয়ে ভাল বক্তব্য। এটা সত্যিই একটি বড় হিট। আমি অনুমান করি যে আমরা করতে পারব random() < 0.02এবং তারপরে সেই তালিকাটি বদলে ফেলব limit 1000! কয়েক হাজার সারিতে (বাতুল) ক্রমটি কম ব্যয়বহুল হবে।
ডোনাল্ড মাইনার

"টেবিল থেকে * নির্বাচন করুন যেখানে এলোমেলো () <0.05 সীমা 500;" Postgresql এর অন্যতম সহজ পদ্ধতি। আমরা আমাদের এমন একটি প্রকল্পে এটি ব্যবহার করেছি যেখানে আমাদের ফলাফলের ৫% নির্বাচন করতে হবে এবং প্রক্রিয়াজাতকরণের জন্য একযোগে 500 সারি নেই।
tgharold

বিশ্বে আপনি কেন 500 মি সারি টেবিলের নমুনা পুনরুদ্ধার করার জন্য কোনও ও (এন) পূর্ণ স্ক্যান বিবেচনা করবেন? এটি হাস্যকরভাবে বড় টেবিলগুলিতে ধীরে ধীরে এবং সম্পূর্ণ অপ্রয়োজনীয়।
মাফু

76

এলোমেলো () দ্বারা postgresql ক্রম, এলোমেলো ক্রমে সারি নির্বাচন করুন:

select your_columns from your_table ORDER BY random()

একটি স্বতন্ত্র সহ এলোমেলো () দ্বারা postgresql ক্রম:

select * from 
  (select distinct your_columns from your_table) table_alias
ORDER BY random()

এলোমেলোভাবে সীমাবদ্ধভাবে এক সারি পোস্টগ্রেসকিএল অর্ডার:

select your_columns from your_table ORDER BY random() limit 1

1
select your_columns from your_table ORDER BY random() limit 145mil সারি নিতে ~ Exec 2 মিনিট
Nguyên

এই গতি বাড়ানোর কোন উপায় আছে?
সিপিল

43

PostgreSQL 9.5 দিয়ে শুরু করে, একটি টেবিল থেকে এলোমেলো উপাদান পাওয়ার জন্য উত্সর্গীকৃত একটি নতুন সিনট্যাক্স রয়েছে:

SELECT * FROM mytable TABLESAMPLE SYSTEM (5);

এই উদাহরণটি আপনাকে এর থেকে 5% উপাদান দেবে mytable

এই ব্লগ পোস্টের উপর আরো ব্যাখ্যা দেখুন: http://www.postgresql.org/docs/current/static/sql-select.html


3
দস্তাবেজগুলির একটি গুরুত্বপূর্ণ নোট: "সিস্টেমে পদ্ধতিটি প্রতিটি ব্লকের সাথে নির্বাচিত হওয়ার নির্দিষ্ট সুযোগ থাকার সাথে ব্লক-স্তরীয় নমুনা দেয়; প্রতিটি নির্বাচিত ব্লকের সমস্ত সারি ফিরে আসে s নির্দিষ্ট করা আছে, তবে এটি ক্লাস্টারিং এফেক্টের ফলাফল হিসাবে টেবিলের কম-এলোমেলো নমুনা ফিরে আসতে পারে। "
টিম

1
শতাংশের পরিবর্তে কয়েকটি সারি নির্দিষ্ট করার উপায় আছে কি?
ফ্লিম

4
আপনি TABLESAMPLE SYSTEM_ROWS(400)400 এলোমেলো সারিগুলির নমুনা পেতে ব্যবহার করতে পারেন । এই বিবৃতিটি ব্যবহার করার জন্য আপনাকে বিল্ট-ইন tsm_system_rowsএক্সটেনশন সক্ষম করতে হবে।
মিকৈল লে বেলিফ

দুর্ভাগ্যক্রমে মুছে ফেলার সাথে কাজ করে না।
গাদেলকারিম

27

অর্ডার বাইরের সাথে ধীরে ধীরে হতে চলেছে।

select * from table where random() < 0.01;রেকর্ড অনুসারে রেকর্ডে যায় এবং এলোমেলোভাবে এটি ফিল্টার করার সিদ্ধান্ত নেয় বা না। এটি হতে চলেছে O(N)কারণ কেবলমাত্র প্রতিটি রেকর্ড একবারে পরীক্ষা করা দরকার।

select * from table order by random() limit 1000;পুরো টেবিলটি বাছাই করতে চলেছে, তারপরে প্রথম 1000 বেছে নিন। পর্দার পিছনে কোনও ভুডু যাদু ছাড়াও, ক্রমটি হচ্ছে O(N * log N)

random() < 0.01একটির নেতিবাচক দিকটি হ'ল আপনি আউটপুট রেকর্ডের একটি পরিবর্তনশীল সংখ্যা পাবেন।


দ্রষ্টব্য, এলোমেলোভাবে বাছাইয়ের চেয়ে ডেটার সেট সেট বদলানোর আরও ভাল উপায় আছে: ফিশার-ইয়েটস সাফল , যা এতে চলে O(N)। এসকিউএল-তে সাফল্য বাস্তবায়ন করা বেশ চ্যালেঞ্জের মতো মনে হচ্ছে।


3
যদিও আপনার প্রথম উদাহরণের শেষে আপনি সীমা 1 যুক্ত করতে পারবেন না এমন কোনও কারণ নেই। কেবলমাত্র সমস্যাটিই এমন একটি সম্ভাবনা যা আপনি কোনও রেকর্ড ফিরে পান না, তাই আপনার কোডটিতে এটি বিবেচনা করতে হবে।
পুনঃপ্রকাশ

ফিশার-ইয়েটসের সমস্যাটি হ'ল এটির থেকে বাছাই করার জন্য আপনার মেমরির পুরো ডেটাসেট থাকা দরকার। খুব বড় ডেটাসেটের জন্য কার্যকর নয় :(
সিপিআইএলএল করুন

16

এখানে একটি সিদ্ধান্ত আমার পক্ষে কাজ করে। আমার ধারণা এটি বোঝার এবং সম্পাদন করা খুব সহজ।

SELECT 
  field_1, 
  field_2, 
  field_2, 
  random() as ordering
FROM 
  big_table
WHERE 
  some_conditions
ORDER BY
  ordering 
LIMIT 1000;

6
আমি মনে করি এই সমাধানটি কাজ করে ORDER BY random()যা কাজ করে তবে একটি বৃহত টেবিলের সাথে কাজ করার সময় দক্ষ নাও হতে পারে।
আনহ কাও

15
select * from table order by random() limit 1000;

আপনি যদি কয়টি সারি চান তা জানেন, পরীক্ষা করে দেখুন tsm_system_rows

tsm_system_rows

মডিউলটি সারণী নমুনা পদ্ধতি SYSTEM_ROWS সরবরাহ করে, যা একটি নির্বাচন কমান্ডের টেবিলসাম্পল ক্লজে ব্যবহার করা যেতে পারে।

এই টেবিলের নমুনা পদ্ধতিটি একটি একক পূর্ণসংখ্যার যুক্তি গ্রহণ করে যা সর্বাধিক সংখ্যক সারি পড়তে হয়। ফলাফলের নমুনায় সর্বদা হ'ল অনেকগুলি সারি থাকে, যদি না টেবিলটিতে পর্যাপ্ত সারি থাকে না, তবে এই ক্ষেত্রে পুরো টেবিলটি নির্বাচন করা হয় is অন্তর্নির্মিত SYSTEM নমুনা পদ্ধতির মতো, SYSTEM_ROWS ব্লক-স্তরীয় নমুনা সম্পাদন করে, যাতে নমুনাটি পুরো এলোমেলো নয় তবে ক্লাস্টারিং এফেক্টের সাথে সম্পর্কিত হতে পারে, বিশেষত যদি কেবলমাত্র একটি সংখ্যক সারি অনুরোধ করা হয়।

প্রথমে এক্সটেনশানটি ইনস্টল করুন

CREATE EXTENSION tsm_system_rows;

তারপরে আপনার প্রশ্ন,

SELECT *
FROM table
TABLESAMPLE SYSTEM_ROWS(1000);

2
আমি আপনার যুক্ত উত্তরে একটি লিঙ্ক যুক্ত করেছি, এটি অন্তর্নির্মিত SYSTEMপদ্ধতির চেয়ে উল্লেখযোগ্য উন্নতি ।
এরউইন ব্র্যান্ডসেটেটার

আমি শুধু একটি প্রশ্নের উত্তর আছে এখানে (র্যান্ডম একক রেকর্ড) সময় আমি যথেষ্ট সঞ্চালিত মাপকাঠিতে এবং পরীক্ষার এর tsm_system_rowsএবং tsm_system_timeএক্সটেনশান নেই। আমি যতদূর দেখতে পাচ্ছি, এগুলি এলোমেলো সারিগুলির একেবারে ন্যূনতম নির্বাচন ছাড়া অন্য কোনও কিছুর জন্য কার্যত অকেজো । আপনি যদি আমার তাত্ক্ষণিকতার সাথে বৈধতা বা বৈধতা সম্পর্কে তাত্ক্ষণিকভাবে নজর দিতে এবং মন্তব্য করতে পারেন তবে আমি কৃতজ্ঞ হব।
ভোরেস

6

আপনি যদি কেবল একটি সারি চান, আপনি offsetথেকে প্রাপ্ত গণনা ব্যবহার করতে পারেন count

select * from table_name limit 1
offset floor(random() * (select count(*) from table_name));

2

আরউইন ব্র্যান্ডস্টেটারের দ্বারা বর্ণিত বস্তুগত দর্শন "সম্ভাব্য বিকল্প" এর একটি প্রকরণ সম্ভব।

উদাহরণস্বরূপ বলুন যে আপনি যে এলোমেলোভাবে মানগুলি ফেরত দিয়েছেন তাতে ডুপ্লিকেট চান না। সুতরাং আপনার মানগুলির (নন-র্যান্ডমাইজড) সেট থাকা প্রাথমিক টেবিলে আপনাকে বুলিয়ান মান সেট করতে হবে।

ধরে নিলাম এটি ইনপুট টেবিল:

id_values  id  |   used
           ----+--------
           1   |   FALSE
           2   |   FALSE
           3   |   FALSE
           4   |   FALSE
           5   |   FALSE
           ...

ID_VALUESপ্রয়োজন মতো টেবিলটি বসান । তারপরে, এরউইনের বর্ণনা অনুসারে একটি বস্তুগত দৃষ্টি তৈরি করুন যা ID_VALUESএকবার টেবিলটিকে এলোমেলো করে দেয় :

CREATE MATERIALIZED VIEW id_values_randomized AS
  SELECT id
  FROM id_values
  ORDER BY random();

নোট করুন যে বস্তুগত দৃশ্যটিতে ব্যবহৃত কলামটি নেই, কারণ এটি দ্রুত পুরানো হয়ে যাবে। এছাড়াও ভিউতে অন্য কলামগুলি id_valuesটেবিলের মধ্যে থাকা থাকতে পারে না ।

প্রাপ্ত করার জন্য (এবং "গ্রাস") র্যান্ডম মূল্যবোধ, একটি অন update-রিটার্নিং ব্যবহার id_valuesনির্বাচন id_valuesথেকে id_values_randomizedএকটি যোগদানের সঙ্গে, এবং শুধুমাত্র প্রাসঙ্গিক সম্ভাবনার প্রাপ্ত আকাঙ্ক্ষিত মানদণ্ড প্রয়োগের। উদাহরণ স্বরূপ:

UPDATE id_values
SET used = TRUE
WHERE id_values.id IN 
  (SELECT i.id
    FROM id_values_randomized r INNER JOIN id_values i ON i.id = r.id
    WHERE (NOT i.used)
    LIMIT 5)
RETURNING id;

LIMITপ্রয়োজনীয় হিসাবে পরিবর্তন করুন - আপনার যদি একবারে কেবল একটি করে এলোমেলো মান প্রয়োজন হয়, তে পরিবর্তন LIMITকরুন 1

যথাযথ সূচকগুলি চালু থাকায় id_values, আমি বিশ্বাস করি যে আপডেট-রিটার্নিং খুব সামান্য লোডের সাথে খুব দ্রুত সম্পাদন করা উচিত। এটি একটি ডাটাবেস রাউন্ড ট্রিপ সহ এলোমেলোভাবে মানগুলি প্রদান করে। "যোগ্য" সারিগুলির মানদণ্ড প্রয়োজনীয়তা মতো জটিল হতে পারে। id_valuesটেবিলে যে কোনও সময় নতুন সারি যুক্ত করা যেতে পারে এবং বস্তুগত দৃশ্যটি রিফ্রেশ হওয়ার সাথে সাথে এগুলি অ্যাপ্লিকেশনটিতে অ্যাক্সেসযোগ্য হয়ে উঠবে (যা সম্ভবত অফ-পিক সময়ে চালানো যেতে পারে)। বস্তুগত দৃশ্যের তৈরি এবং রিফ্রেশটি ধীর গতির হবে, তবে কেবলমাত্র id_valuesটেবিলে নতুন আইডি যুক্ত করা হলে এটি সম্পাদন করা দরকার ।


খুব আকর্ষণীয়. আমার যদি কেবলমাত্র নির্বাচিত না হয়ে সিটি আপডেট ব্যবহার করার প্রয়োজন হয় তবে তা কি কাজ করবে? পিজি_ট্রি_এডভিসররি_এক্স্যাক্ট_লকের সাথে আপডেট করার জন্য? (অর্থাত আমার অনেক সমকালীন পাঠ্য এবং লেখাগুলি প্রয়োজন)
ম্যাথিউ

1

আমার অভিজ্ঞতা থেকে একটি পাঠ:

offset floor(random() * N) limit 1চেয়ে দ্রুত নয় order by random() limit 1

আমি ভেবেছিলাম offsetপদ্ধতির দ্রুততর হবে কারণ এটি পোস্টগ্রিসে বাছাইয়ের সময় বাঁচায়। দেখা গেল এটি ছিল না।


0

rটাইপ সহ ডাকা একটি কলাম যুক্ত করুন serial। সূচকr

ধরুন আমাদের 200,000 সারি রয়েছে, আমরা একটি এলোমেলো সংখ্যা তৈরি করতে যাচ্ছি nযেখানে 0 <<n <<= 200, 000।

এর সাথে সারি নির্বাচন করুন r > n, তাদের বাছাই করুনASC এবং সবচেয়ে ছোটটি নির্বাচন করুন।

কোড:

select * from YOUR_TABLE 
where r > (
    select (
        select reltuples::bigint AS estimate
        from   pg_class
        where  oid = 'public.YOUR_TABLE'::regclass) * random()
    )
order by r asc limit(1);

কোডটি স্ব-বর্ণনামূলক। মাঝের সাবকোয়ারিটি https://stackoverflow.com/a/7945274/1271094 থেকে টেবিলের সারি গণনার দ্রুত অনুমান করতে ব্যবহৃত হয়

অ্যাপ্লিকেশন স্তরে আপনার আবার বিবৃতি কার্যকর করতে হবে যদি n> সারিগুলির সংখ্যা বা একাধিক সারি নির্বাচন করা প্রয়োজন।


আমি এটি পছন্দ করি কারণ এটি সংক্ষিপ্ত এবং মার্জিত :) এবং আমি এটির উন্নতি করার একটি উপায়ও পেয়েছি: ব্যাখ্যা আনালাইজে আমাকে বলে যে এর মতো, কোনও পিকেই সূচক ব্যবহার করা হবে না কারণ এলোমেলো () ডাবল ফেরত দেয়, অন্যদিকে পিকেইতে একটি বড় দরকার হয়।
fxtentacle

আপনার আধ্যাত্মিক স্থানে যেখানে r> নির্বাচন করুন (নির্বাচন করুন (পুনঃনির্মাণ নির্বাচন করুন: বিগিন্ট হিসাবে পিজি_ক্লাস থেকে অনুমান হিসাবে যেখানে oid = 'সর্বজনীন।
fxtentacle

0

আমি জানি আমি পার্টিতে কিছুটা দেরি করেছি, তবে আমি সবেমাত্র পিজ_সাম্পল নামে একটি দুর্দান্ত সরঞ্জামটি পেয়েছি :

pg_sample - রেফারেন্সিয়াল অখণ্ডতা বজায় রাখার সময় একটি বৃহত্তর পোস্টগ্রাইএসকিউএল ডাটাবেস থেকে একটি ছোট, নমুনা ডেটাসেট উত্তোলন করুন।

আমি এটি একটি 350 এম সারির ডাটাবেসের সাহায্যে চেষ্টা করেছি এবং এটি সত্যিই দ্রুত ছিল, এলোমেলোতা সম্পর্কে জানেন না ।

./pg_sample --limit="small_table = *" --limit="large_table = 100000" -U postgres source_db | psql -U postgres target_db
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.