PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

रैंडम टुपल्स प्राप्त करने के लिए टेबल्स नमूना और अन्य तरीके

PostgreSQL का TABLESAMPLE यादृच्छिक टुपल्स प्राप्त करने के अन्य पारंपरिक तरीकों की तुलना में कुछ अधिक लाभ लाता है।

TABLESAMPLE एक SQL SELECT क्लॉज है और यह दो सैंपलिंग मेथड प्रदान करता है जो SYSTEM . हैं और BERNOULLI . TABLESAMPLE . की सहायता से हम तालिका से यादृच्छिक पंक्तियों को आसानी से प्राप्त कर सकते हैं। TABLESAMPLE के बारे में और पढ़ने के लिए आप पिछले ब्लॉग पोस्ट को देख सकते हैं

इस ब्लॉग पोस्ट में हम यादृच्छिक पंक्तियाँ प्राप्त करने के वैकल्पिक तरीकों के बारे में बात करेंगे। TABLESAMPLE . से पहले लोग कैसे यादृच्छिक पंक्तियों का चयन कर रहे थे , अन्य तरीकों के फायदे और नुकसान क्या हैं और TABLESAMPLE से हमें क्या हासिल हुआ ?

यादृच्छिक पंक्तियों को चुनने के बारे में बहुत बढ़िया ब्लॉग पोस्ट हैं, आप इस विषय की गहरी समझ हासिल करने के लिए निम्नलिखित ब्लॉग पोस्ट पढ़ना शुरू कर सकते हैं।

यादृच्छिक पंक्ति प्राप्त करने के मेरे विचार

डेटाबेस तालिका से यादृच्छिक पंक्तियाँ प्राप्त करना

random_agg ()

आइए तालिका से यादृच्छिक पंक्तियों को प्राप्त करने के पारंपरिक तरीकों की तुलना TABLESAMPLE द्वारा प्रदान किए गए नए तरीकों से करें।

TABLESAMPLE . से पहले क्लॉज, तालिका से पंक्तियों को बेतरतीब ढंग से चुनने के लिए आमतौर पर इस्तेमाल की जाने वाली 3 विधियाँ थीं।

1- यादृच्छिक द्वारा आदेश()

परीक्षण उद्देश्यों के लिए हमें एक तालिका बनाने और उसके अंदर कुछ डेटा डालने की आवश्यकता है।

आइए ts_test तालिका बनाएं और उसमें 1M पंक्तियाँ डालें:

CREATE TABLE ts_test (
  id SERIAL PRIMARY KEY,
  title TEXT
);

INSERT INTO ts_test (title)
SELECT
    'Record #' || i
FROM
    generate_series(1, 1000000) i;

10 यादृच्छिक पंक्तियों को चुनने के लिए निम्नलिखित SQL कथन को ध्यान में रखते हुए:

SELECT * FROM ts_test ORDER BY random() LIMIT 10;

PostgreSQL को एक पूर्ण तालिका स्कैन करने और ऑर्डर करने का कारण बनता है। इसलिए प्रदर्शन कारणों से बड़ी संख्या में पंक्तियों वाली तालिकाओं के लिए यह विधि पसंद नहीं की जाती है।

आइए देखें EXPLAIN ANALYZE ऊपर इस क्वेरी का आउटपुट:

random=# EXPLAIN ANALYZE SELECT * FROM ts_test ORDER BY random() LIMIT 10;
 QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------
 Limit (cost=33959.03..33959.05 rows=10 width=36) (actual time=1956.786..1956.807 rows=10 loops=1)
 -> Sort (cost=33959.03..35981.18 rows=808863 width=36) (actual time=1956.780..1956.789 rows=10 loops=1)
 Sort Key: (random())
 Sort Method: top-N heapsort Memory: 25kB
 -> Seq Scan on ts_test (cost=0.00..16479.79 rows=808863 width=36) (actual time=0.276..1001.109 rows=1000000 loops=1)
 Planning time: 1.434 ms
 Execution time: 1956.900 ms
(7 rows)

EXPLAIN ANALYZE . के रूप में बताते हैं, 1M पंक्तियों में से 10 का चयन करने में लगभग 2 सेकंड का समय लगा। क्वेरी ने random() . के आउटपुट का भी उपयोग किया परिणामों को ऑर्डर करने के लिए सॉर्ट कुंजी के रूप में। छँटाई यहाँ सबसे अधिक समय लेने वाला कार्य प्रतीत होता है। आइए इसे TABLESAMPLE . का उपयोग करके परिदृश्य के साथ निष्पादित करें ।

PostgreSQL 9.5 में, यादृच्छिक रूप से पंक्तियों की सटीक संख्या प्राप्त करने के लिए, हम SYSTEM_ROWS नमूनाकरण विधि का उपयोग कर सकते हैं। tsm_system_rows . द्वारा प्रदान किया गया contrib मॉड्यूल, यह हमें यह निर्दिष्ट करने की अनुमति देता है कि नमूना द्वारा कितनी पंक्तियों को वापस किया जाना चाहिए। आम तौर पर केवल अनुरोधित प्रतिशत को TABLESAMPLE SYSTEM . के साथ निर्दिष्ट किया जा सकता है और BERNOULLI तरीके।

सबसे पहले, हमें tsm_system_rows create बनाना चाहिए दोनों TABLESAMPLE SYSTEM . के बाद से इस पद्धति का उपयोग करने के लिए एक्सटेंशन और TABLESAMPLE BERNOULLI विधियाँ इस बात की गारंटी नहीं देती हैं कि प्रदत्त प्रतिशत के परिणामस्वरूप पंक्तियों की अपेक्षित संख्या होगी। कृपया पिछला TABLESAMPLE p देखें याद करने के लिए कि वे इस तरह क्यों काम करते हैं।

आइए tsm_system_rows creating बनाकर शुरू करते हैं विस्तार:

random=# CREATE EXTENSION tsm_system_rows;
CREATE EXTENSION

अब तुलना करते हैं “ORDER BY random() " EXPLAIN ANALYZE EXPLAIN ANALYZE . के साथ आउटपुट tsm_system_rows . का आउटपुट क्वेरी जो 1M पंक्ति तालिका में से 10 यादृच्छिक पंक्तियाँ लौटाती है।

random=# EXPLAIN ANALYZE SELECT * FROM ts_test TABLESAMPLE SYSTEM_ROWS(10);
 QUERY PLAN
-------------------------------------------------------------------------------------------------------
 Sample Scan on ts_test (cost=0.00..4.10 rows=10 width=18) (actual time=0.069..0.083 rows=10 loops=1)
 Sampling: system_rows ('10'::bigint)
 Planning time: 0.646 ms
 Execution time: 0.159 ms
(4 rows)

पूरी क्वेरी में 0.159 एमएस लगा। यह नमूनाकरण विधि "ORDER BY random() . की तुलना में बहुत तेज़ है ”विधि जिसमें 1956.9 एमएस लिया।

2- random() से तुलना करें

निम्न SQL हमें 10% संभावना के साथ यादृच्छिक पंक्तियों को पुनः प्राप्त करने की अनुमति देता है

SELECT * FROM ts_test WHERE random() <= 0.1;

यह विधि रैंडम द्वारा ऑर्डर करने की तुलना में तेज़ है क्योंकि यह चयनित पंक्तियों को सॉर्ट नहीं करती है। यह BERNOULLI . की तरह तालिका से पंक्तियों का अनुमानित प्रतिशत लौटाएगा या SYSTEM TABLESAMPLE तरीके।

आइए देखें EXPLAIN ANALYZE random() . का आउटपुट ऊपर क्वेरी:

random=# EXPLAIN ANALYZE SELECT * FROM ts_test WHERE random() <= 0.1;
 QUERY PLAN
------------------------------------------------------------------------------------------------------------------
 Seq Scan on ts_test (cost=0.00..21369.00 rows=333333 width=18) (actual time=0.089..280.483 rows=100014 loops=1)
 Filter: (random() <= '0.1'::double precision)
 Rows Removed by Filter: 899986
 Planning time: 0.704 ms
 Execution time: 367.527 ms
(5 rows)

क्वेरी ने 367.5 एमएस लिया। ORDER BY random() . से बहुत बेहतर है . लेकिन सटीक पंक्ति गणना को नियंत्रित करना कठिन है। आइए तुलना करें "random() " EXPLAIN ANALYZE EXPLAIN ANALYZE . के साथ आउटपुट TABLESAMPLE BERNOULLI . का आउटपुट क्वेरी जो 1M पंक्तियों की तालिका में से लगभग 10% यादृच्छिक पंक्तियों को लौटाती है।

random=# EXPLAIN ANALYZE SELECT * FROM ts_test TABLESAMPLE BERNOULLI (10);
 QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
 Sample Scan on ts_test  (cost=0.00..7369.00 rows=100000 width=18) (actual time=0.015..147.002 rows=100155 loops=1)
   Sampling: bernoulli ('10'::real)
 Planning time: 0.076 ms
 Execution time: 239.289 ms
(4 rows)

हमने BERNOULLI . के पैरामीटर के रूप में 10 दिए हैं क्योंकि हमें सभी रिकॉर्ड का 10% चाहिए।

यहाँ हम देख सकते हैं कि BERNOULLI विधि को निष्पादित करने में 239.289 ms का समय लगा। ये दोनों विधियां उनके काम करने के तरीके में काफी समान हैं, BERNOULLI थोड़ा तेज है क्योंकि यादृच्छिक चयन सभी निचले स्तर पर किया जाता है। BERNOULLI . का उपयोग करने का एक लाभ WHERE random() <= 0.1 . की तुलना में REPEATABLE है क्लॉज जिसे हमने पिछले TABLESAMPLE . में वर्णित किया था पोस्ट।

3- यादृच्छिक मान वाला अतिरिक्त कॉलम

यह विधि यादृच्छिक रूप से असाइन किए गए मानों के साथ एक नया कॉलम जोड़ने, उसमें एक इंडेक्स जोड़ने, उस कॉलम द्वारा सॉर्टिंग करने और वैकल्पिक रूप से वितरण को यादृच्छिक बनाने के लिए समय-समय पर अपने मानों को अपडेट करने का सुझाव देती है।

यह रणनीति ज्यादातर दोहराने योग्य यादृच्छिक नमूनाकरण की अनुमति देती है। यह पहली विधि की तुलना में बहुत तेज़ी से काम करता है लेकिन पहली बार सेटअप करने के लिए प्रयास करता है, और इसके परिणामस्वरूप संचालन को सम्मिलित करने, अद्यतन करने और हटाने में एक प्रदर्शन लागत आती है।

आइए इस विधि को हमारे ts_test . पर लागू करें टेबल।

सबसे पहले, हम randomcolumn . नामक एक नया कॉलम जोड़ेंगे डबल सटीक प्रकार के साथ क्योंकि PostgreSQL का random() फ़ंक्शन एक संख्या को दोहरी सटीकता में लौटाता है।

random=# ALTER TABLE ts_test ADD COLUMN randomcolumn DOUBLE PRECISION;
ALTER TABLE

फिर हम random() . का इस्तेमाल करके नए कॉलम को अपडेट करेंगे समारोह।

random=# \timing
Timing is on.
random=# BEGIN;
BEGIN
Time: 2.071 ms
random=# UPDATE ts_test SET randomcolumn = RANDOM();
UPDATE 1000000
Time: 8483.741 ms
random=# COMMIT;
COMMIT
Time: 2.615 ms

एक नया कॉलम बनाने और उस नए कॉलम को यादृच्छिक (0.0-1.0) मानों के साथ पॉप्युलेट करने के लिए इस पद्धति की प्रारंभिक लागत है, लेकिन यह एक बार की लागत है। इस उदाहरण में, 1M पंक्तियों के लिए, इसमें लगभग 8.5 सेकंड का समय लगा।

आइए देखें कि हमारी नई विधि से 100 पंक्तियों को क्वेरी करके हमारे परिणाम प्रतिलिपि प्रस्तुत करने योग्य हैं या नहीं:

random=# SELECT * FROM ts_test ORDER BY randomcolumn LIMIT 100;
 -------+---------------+----------------------
 13522  | Record #13522  | 6.4261257648468e-08
 671584 | Record #671584 | 6.4261257648468e-07
 714012 | Record #714012 | 1.95764005184174e-06
 162016 | Record #162016 | 3.44449654221535e-06
 106867 | Record #106867 | 3.66196036338806e-06
 865669 | Record #865669 | 3.96883115172386e-06
 927    | Record #927    | 4.65428456664085e-06
 526017 | Record #526017 | 4.65987250208855e-06
 98338  | Record #98338  | 4.91179525852203e-06
 769625 | Record #769625 | 4.91319224238396e-06
 ...
 462484 | Record #462484 | 9.83504578471184e-05
 (100 rows)

जब हम ऊपर दी गई क्वेरी को निष्पादित करते हैं, तो हमें ज्यादातर एक ही परिणाम सेट मिलता है लेकिन इसकी गारंटी नहीं है क्योंकि हमने random() का उपयोग किया है randomcolumn pop को भरने के लिए कार्य मान और इस मामले में एक से अधिक स्तंभों का मान समान हो सकता है। यह सुनिश्चित करने के लिए कि हर बार चलने पर हमें समान परिणाम मिले, हमें ORDER BY में आईडी कॉलम जोड़कर अपनी क्वेरी में सुधार करना चाहिए खंड, इस तरह हम यह सुनिश्चित करते हैं कि ORDER BY क्लॉज पंक्तियों का एक अनूठा सेट निर्दिष्ट करता है, क्योंकि आईडी कॉलम में प्राथमिक कुंजी इंडेक्स होता है।

अब नीचे दी गई बेहतर क्वेरी को चलाते हैं:

random=# SELECT * FROM ts_test ORDER BY randomcolumn, id LIMIT 100;
 id | title | randomcolumn
--------+----------------+----------------------
 13522  | Record #13522  | 6.4261257648468e-08
 671584 | Record #671584 | 6.4261257648468e-07
 714012 | Record #714012 | 1.95764005184174e-06
 162016 | Record #162016 | 3.44449654221535e-06
 106867 | Record #106867 | 3.66196036338806e-06
 865669 | Record #865669 | 3.96883115172386e-06
 927    | Record #927    | 4.65428456664085e-06
 526017 | Record #526017 | 4.65987250208855e-06
 98338  | Record #98338  | 4.91179525852203e-06
 769625 | Record #769625 | 4.91319224238396e-06 
 ...
 462484 | Record #462484 | 9.83504578471184e-05
 (100 rows)

अब हमें यकीन है कि हम इस पद्धति का उपयोग करके पुनरुत्पादित यादृच्छिक नमूना प्राप्त कर सकते हैं।

यह देखने का समय है EXPLAIN ANALYZE हमारी अंतिम क्वेरी के परिणाम:

random=# EXPLAIN ANALYZE SELECT * FROM ts_test ORDER BY randomcolumn, id LIMIT 100;
 QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------
 Limit (cost=55571.28..55571.53 rows=100 width=26) (actual time=1951.811..1952.039 rows=100 loops=1)
 -> Sort (cost=55571.28..58071.28 rows=1000000 width=26) (actual time=1951.804..1951.891 rows=100 loops=1)
 Sort Key: randomcolumn, id
 Sort Method: top-N heapsort Memory: 32kB
 -> Seq Scan on ts_test (cost=0.00..17352.00 rows=1000000 width=26) (actual time=0.058..995.011 rows=1000000 loops=1)
 Planning time: 0.481 ms
 Execution time: 1952.215 ms
(7 rows)

इस विधि की तुलना TABLESAMPLE . से करने के लिए विधियाँ, आइए चुनें SYSTEM REPEATABLE के साथ विधि विकल्प, क्योंकि यह विधि हमें प्रतिलिपि प्रस्तुत करने योग्य परिणाम देती है।

TABLESAMPLE SYSTEM विधि मूल रूप से ब्लॉक/पेज स्तरीय नमूनाकरण करती है; यह डिस्क से यादृच्छिक पृष्ठों को पढ़ता है और लौटाता है। इस प्रकार यह टपल स्तर के बजाय पृष्ठ स्तर पर यादृच्छिकता प्रदान करता है। इसलिए पुनर्प्राप्त की गई पंक्तियों की गणना को ठीक से नियंत्रित करना कठिन है। यदि कोई पृष्ठ नहीं चुना गया है तो हमें कोई परिणाम नहीं मिल सकता है। पृष्ठ स्तरीय नमूनाकरण भी क्लस्टरिंग प्रभाव के लिए प्रवण है।

TABLESAMPLE SYNTAX BERNOULLI . के लिए समान है और SYSTEM विधियों में, हम प्रतिशत निर्दिष्ट करेंगे जैसे हमने BERNOULLI . में किया था विधि।

त्वरित अनुस्मारक: सिंटैक्स

SELECT select_expression
FROM table_name
TABLESAMPLE sampling_method ( argument [, ...] ) [ REPEATABLE ( seed ) ]
...

लगभग 100 पंक्तियों को पुनः प्राप्त करने के लिए, हमें 100 * 100 / 1 000 000 =0.01% तालिका की पंक्तियों का अनुरोध करना होगा। तो हमारा प्रतिशत 0.01 होगा।

क्वेरी शुरू करने से पहले, आइए याद रखें कि कैसे REPEATABLE काम करता है। मूल रूप से हम एक बीज पैरामीटर चुनेंगे और जब हम पिछली क्वेरी के साथ उसी बीज का उपयोग करेंगे तो हमें हर बार समान परिणाम मिलेंगे। अगर हम एक अलग बीज प्रदान करते हैं तो क्वेरी एक बिल्कुल अलग परिणाम सेट देगी।

आइए क्वेरी के साथ परिणाम देखने का प्रयास करें।

random=# Select * from ts_test tablesample system (0.01) repeatable (60);
 id | title | randomcolumn
--------+----------------+---------------------
 659598 | Record #659598 | 0.964113113470376
 659599 | Record #659599 | 0.531714483164251
 659600 | Record #659600 | 0.477636905387044
 659601 | Record #659601 | 0.861940925940871
 659602 | Record #659602 | 0.545977566856891
 659603 | Record #659603 | 0.326795583125204
 659604 | Record #659604 | 0.469275736715645
 659605 | Record #659605 | 0.734953186474741
 659606 | Record #659606 | 0.41613544523716
 ...
 659732 | Record #659732 | 0.893704727292061
 659733 | Record #659733 | 0.847225237637758
 (136 rows)

हमें 136 पंक्तियाँ मिलती हैं, जैसा कि आप समझ सकते हैं कि यह संख्या इस बात पर निर्भर करती है कि एक पृष्ठ में कितनी पंक्तियाँ संग्रहीत हैं।

आइए अब उसी क्वेरी को उसी सीड नंबर के साथ चलाने का प्रयास करें:

random=# Select * from ts_test tablesample system (0.01) repeatable (60);
 id | title | randomcolumn
--------+----------------+---------------------
 659598 | Record #659598 | 0.964113113470376
 659599 | Record #659599 | 0.531714483164251
 659600 | Record #659600 | 0.477636905387044
 659601 | Record #659601 | 0.861940925940871
 659602 | Record #659602 | 0.545977566856891
 659603 | Record #659603 | 0.326795583125204
 659604 | Record #659604 | 0.469275736715645
 659605 | Record #659605 | 0.734953186474741
 659606 | Record #659606 | 0.41613544523716 
 ...
 659732 | Record #659732 | 0.893704727292061
 659733 | Record #659733 | 0.847225237637758
 (136 rows)

REPEATABLE . की बदौलत हमें वही परिणाम सेट मिलता है विकल्प। अब हम तुलना कर सकते हैं TABLESAMPLE SYSTEM EXPLAIN ANALYZE . देखकर यादृच्छिक स्तंभ विधि के साथ विधि आउटपुट।

random=# EXPLAIN ANALYZE SELECT * FROM ts_test TABLESAMPLE SYSTEM (0.01) REPEATABLE (60);
 QUERY PLAN
---------------------------------------------------------------------------------------------------------
 Sample Scan on ts_test (cost=0.00..5.00 rows=100 width=26) (actual time=0.091..0.230 rows=136 loops=1)
 Sampling: system ('0.01'::real) REPEATABLE ('60'::double precision)
 Planning time: 0.323 ms
 Execution time: 0.398 ms
(4 rows)

SYSTEM विधि नमूना स्कैन का उपयोग करती है और यह बहुत तेज़ है। इस पद्धति का एकमात्र पिछड़ापन यह है कि हम गारंटी नहीं दे सकते कि प्रदान किए गए प्रतिशत के परिणामस्वरूप पंक्तियों की अपेक्षित संख्या होगी।

निष्कर्ष

इस ब्लॉग पोस्ट में हमने मानक TABLESAMPLE . की तुलना की है (SYSTEM , BERNOULLI ) और tsm_system_rows पुराने यादृच्छिक तरीकों के साथ मॉड्यूल।

यहां आप जल्दी से निष्कर्षों की समीक्षा कर सकते हैं:

  • ORDER BY random() छँटाई के कारण धीमा है
  • random() <= 0.1 BERNOULLI . के समान है विधि
  • यादृच्छिक मान के साथ कॉलम जोड़ने के लिए प्रारंभिक कार्य की आवश्यकता होती है और इससे प्रदर्शन संबंधी समस्याएं हो सकती हैं
  • SYSTEM तेज़ है लेकिन पंक्तियों की संख्या को नियंत्रित करना कठिन है
  • tsm_system_rows तेज़ है और पंक्तियों की संख्या को नियंत्रित कर सकता है

परिणामस्वरूप tsm_system_rows केवल कुछ यादृच्छिक पंक्तियों को चुनने के लिए किसी अन्य विधि को मात देता है।

लेकिन असली विजेता निश्चित रूप से है TABLESAMPLE अपने आप। इसकी एक्स्टेंसिबिलिटी, कस्टम एक्सटेंशन (यानी tsm_system_rows . के लिए धन्यवाद , tsm_system_time ) को TABLESAMPLE . का उपयोग करके विकसित किया जा सकता है विधि कार्य।

डेवलपर नोट: कस्टम नमूनाकरण विधियों को लिखने के तरीके के बारे में अधिक जानकारी PostgreSQL दस्तावेज़ीकरण के एक तालिका नमूनाकरण विधि अध्याय लिखना में मिल सकती है।

भविष्य के लिए नोट: हम अपने अगले TABLESAMPLE में AXLE प्रोजेक्ट और tsm_system_time एक्सटेंशन पर चर्चा करेंगे ब्लॉग पोस्ट।


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL उपयोगकर्ता बनाना और उन्हें डेटाबेस में जोड़ना

  2. psycopg2 बड़ी क्वेरी के बाद मेमोरी लीक कर रहा है

  3. कैसे विशाल तालिका से सभी पंक्तियों को पढ़ने के लिए?

  4. सम्मिलित नहीं किया जा सकता:त्रुटि:सरणी मान { या आयाम जानकारी . से प्रारंभ होना चाहिए

  5. क्या मैं पहले से ही बनाए जाने के बाद, PostgreSQL तालिका में एक अद्वितीय बाधा जोड़ सकता हूं?