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

सीटीई और जन्मदिन विरोधाभास

विल लेइनवेबर ने पोस्टग्रेज ओपन से एक दिलचस्प सवाल ट्वीट किया है:

-- this returns a different result each time it is ran
with recursive s as (
  select random()
union
  select random() from s
) select count(*) from s;

मुझे यह उदाहरण पसंद है:एक आश्चर्यजनक परिणाम, जिसे सीटीई व्यवहार (और वास्तव में समझाने में मदद करता है) द्वारा समझाया जा सकता है।

अप्रत्याशित सत्य को "विरोधाभास" शब्द से दर्शाया जाता है, और वास्तव में यह एक अभिव्यक्ति (एक "उदाहरण", प्रोग्रामर के शब्दजाल में) है जिसे जन्मदिन विरोधाभास के रूप में जाना जाता है। ।

इसका सबसे सरल सूत्र शायद यह है:यदि आप यादृच्छिक रूप से 23 व्यक्तियों को चुनते हैं, तो संभावना है कि उनमें से दो का जन्मदिन एक ही है, 50% से अधिक है।

परिणाम अप्रत्याशित है, क्योंकि 366 अलग-अलग जन्मदिन हैं, और संख्या 23 366 की तुलना में बहुत छोटी लगती है।

हालाँकि यह सही है, क्योंकि इसे प्रत्यक्ष गणना के साथ दिखाया जा सकता है। PostgreSQL में हम एक और पुनरावर्ती CTE चला सकते हैं:

WITH RECURSIVE r(i,acc) AS (
  SELECT 1, 1 :: double precision
UNION
  SELECT i + 1,
    acc * (((366 - i) :: double precision) / 366)
  FROM r WHERE acc > 0.5
) SELECT count(1) FROM r;

परिणाम के रूप में 23 का उत्पादन।

एक पुनरावर्ती CTE तब रुक जाता है जब पुनरावर्ती चरण कोई नई पंक्तियाँ नहीं जोड़ता है। पिछली क्वेरी में, acc इस संभावना का प्रतिनिधित्व करता है कि पहला i जन्मदिन अलग होते हैं, इसलिए जब संख्या 50% से अधिक न हो तो पुनरावर्तन रुक जाता है।

शुरुआत में उल्लिखित क्वेरी में, जिसे हम संक्षेप में "यादृच्छिक क्वेरी" कहते हैं, पुनरावर्ती CTE समाप्त हो जाता है जब random() एक नई पंक्ति नहीं जोड़ता है। यही है, जब पिछले पुनरावृत्ति में यादृच्छिक रूप से गणना मूल्य की गणना पहले ही की जा चुकी है; ऐसा इसलिए है क्योंकि पुनरावर्ती CTE UNION . का उपयोग कर रहा है UNION ALL . के बजाय ।

यह वास्तव में जन्मदिन का विरोधाभास है, जिसमें 366 को अलग-अलग मानों की अधिकतम संभव संख्या द्वारा प्रतिस्थापित किया गया है जो random() उत्पन्न करना संभव है। वह संख्या वास्तव में क्या है?

random() फ़ंक्शन एक दोहरा सटीक मान देता है, जिसकी सटीक परिभाषा सिस्टम पर निर्भर करती है। हालांकि, सभी दोहरे सटीक मूल्यों का उत्पादन नहीं किया जा सकता है; अंतर्निहित सी फ़ंक्शन दोहरे सटीक मान के बिट आकार की परवाह किए बिना, 2^31 अलग-अलग परिणाम उत्पन्न कर सकता है। यह व्यवहार में काफी अच्छा है, और साथ ही सभी विभिन्न आर्किटेक्चर और पुस्तकालय कार्यान्वयन के साथ संगतता सुनिश्चित की जाती है।

इसलिए हम अपनी क्वेरी में 366 को 2^31 से बदल सकते हैं, और 23 के बजाय हमें उत्तर के रूप में 54563 मिलते हैं।

क्या यह यादृच्छिक क्वेरी के वास्तविक आउटपुट के करीब आता है? आइए हम इसे कुछ बार चलाते हैं, परिणाम एकत्र करते हैं, और औसत की गणना करते हैं:

gianni=# create table t(n int);
CREATE TABLE

gianni=# with recursive s as (
  select random()
union
  select random() from s
) insert into t select count(1) from s;
INSERT 0 1

/* repeat the last query 49 times */

gianni=# select count(1), avg(n) from t;

 count | avg
-------+--------------------
    50 | 54712.060000000000
 (1 row)

वास्तविक परिणामों का औसत 54563 की अपेक्षित सीमा के काफी करीब है; अंतर 0.3% से कम है, काफी रूढ़िवादी रूप से , हम कह सकते हैं!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. क्या सबक्वायरी में ऑर्डर संरक्षित होने की गारंटी है?

  2. PostgreSQL का उपयोग करके पिछले 24 घंटों के रिकॉर्ड का चयन कैसे करें

  3. पोस्टग्रेज में ISO-8601 ग्रेगोरियन डेट टेबल कैसे बनाएं

  4. अपने उपयोगकर्ताओं को खुद को फोर्क करने के लिए कह रहा है

  5. एप्लिकेशन, कनेक्शन पूलिंग और पोस्टग्रेएसक्यूएल के लिए एक सुरक्षा प्रणाली - एलडीएपी के लिए मामला