Postgres में मुझे विंडो फ़ंक्शन का एग्रीगेट कैसे मिलेगा?


11

मेरे पास एक तालिका है जिसमें पूर्णांक सरणियों के क्रमपरिवर्तन / संयोजन के दो कॉलम और एक तीसरा कॉलम है, जिसमें मान है:

CREATE TABLE foo
(
  perm integer[] NOT NULL,
  combo integer[] NOT NULL,
  value numeric NOT NULL DEFAULT 0
);
INSERT INTO foo
VALUES
( '{3,1,2}', '{1,2,3}', '1.1400' ),
( '{3,1,2}', '{1,2,3}', '0' ),
( '{3,1,2}', '{1,2,3}', '1.2680' ),
( '{3,1,2}', '{1,2,3}', '0' ),
( '{3,1,2}', '{1,2,3}', '1.2680' ),
( '{3,1,2}', '{1,2,3}', '0' ),
( '{3,1,2}', '{1,2,3}', '0' ),
( '{3,1,2}', '{1,2,3}', '1.2680' ),
( '{3,1,2}', '{1,2,3}', '0.9280' ),
( '{3,1,2}', '{1,2,3}', '0' ),
( '{3,1,2}', '{1,2,3}', '1.2680' ),
( '{3,1,2}', '{1,2,3}', '0' ),
( '{3,1,2}', '{1,2,3}', '0' ),
( '{3,1,2}', '{1,2,3}', '1.2680' ),
( '{3,1,2}', '{1,2,3}', '0' ),
( '{3,2,1}', '{1,2,3}', '0' ),
( '{3,2,1}', '{1,2,3}', '0.8000' )

मैं प्रत्येक क्रमपरिवर्तन के लिए औसत और मानक विचलन का पता लगाना चाहता हूं, साथ ही प्रत्येक संयोजन के लिए भी। मैं इस प्रश्न के साथ कर सकता हूं:

SELECT
  f1.perm,
  f2.combo,
  f1.perm_average_value,
  f2.combo_average_value,
  f1.perm_stddev,
  f2.combo_stddev,
  f1.perm_count,
  f2.combo_count
FROM
(
  SELECT
    perm,
    combo,
    avg( value ) AS perm_average_value,
    stddev_pop( value ) AS perm_stddev,
    count( * ) AS perm_count
  FROM foo
  GROUP BY perm, combo
) AS f1
JOIN
(
  SELECT
    combo,
    avg( value ) AS combo_average_value,
    stddev_pop( value ) AS combo_stddev,
    count( * ) AS combo_count
  FROM foo
  GROUP BY combo
) AS f2 ON ( f1.combo = f2.combo );

हालांकि, जब मेरे पास बहुत अधिक डेटा होता है, तो यह क्वेरी बहुत धीमी हो सकती है, क्योंकि "फू" तालिका (जो वास्तव में, लगभग 4 मिलियन पंक्तियों के साथ 14 विभाजन होते हैं) को दो बार स्कैन करने की आवश्यकता होती है।

हाल ही में, मुझे पता चला कि पोस्टग्रैज "विंडो फंक्शंस" का समर्थन करता है, जो मूल रूप से एक विशेष कॉलम के लिए ग्रुप बीवाई की तरह है। मैंने अपनी क्वेरी को इन जैसे उपयोग करने के लिए संशोधित किया:

SELECT
  perm,
  combo,
  avg( value ) as perm_average_value,
  avg( avg( value ) ) over w_combo AS combo_average_value,
  stddev_pop( value ) as perm_stddev,
  stddev_pop( avg( value ) ) over w_combo as combo_stddev,
  count( * ) as perm_count,
  sum( count( * ) ) over w_combo AS combo_count
FROM foo
GROUP BY perm, combo
WINDOW w_combo AS ( PARTITION BY combo );

हालांकि यह "कॉम्बो_काउंट" कॉलम के लिए काम करता है, "कॉम्बो_आवर्स_वेल्यू" और "कॉम्बो_स्टीडदेव" कॉलम अब सटीक नहीं हैं। ऐसा प्रतीत होता है कि प्रत्येक क्रमपरिवर्तन के लिए औसत लिया जा रहा है, और फिर प्रत्येक संयोजन के लिए दूसरी बार औसत किया जा रहा है, जो गलत है।

मैं इसे कैसे ठीक करूं? क्या विंडो फ़ंक्शंस का उपयोग यहां अनुकूलन के रूप में भी किया जा सकता है?


वर्तमान संस्करण मानकर पोस्ट 9.2? विंडो फ़ंक्शंस 8.4 के साथ आए।
एरविन ब्रान्डसेट्टर

क्षमा करें, मैं निर्दिष्ट करना भूल गया। हां मैं नवीनतम का उपयोग कर रहा हूं, पोस्टग्रेज 9.2.4।
स्कॉट स्मॉल

जवाबों:


9

एकल क्वेरी स्तर में कुल कार्यों के परिणाम में आपके पास विंडो फ़ंक्शन हो सकते हैं।

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

SELECT perm
      ,combo
      ,avg(value)                 AS perm_average_value
      ,sum(avg(value) * count(*)) OVER w_combo /
       sum(count(*)) OVER w_combo AS combo_average_value
      ,stddev_pop(value)          AS perm_stddev
      ,0                          AS combo_stddev  -- doesn't work!
      ,count(*)                   AS perm_count
      ,sum(count(*)) OVER w_combo AS combo_count
FROM   foo
GROUP  BY perm, combo
WINDOW w_combo  AS (PARTITION BY combo);

आपके लिए combo_average_valueइस अभिव्यक्ति की आवश्यकता होगी

sum(avg(value) * count(*)) OVER w_combo / sum(count(*)) OVER w_combo

चूंकि आपको एक भारित औसत की आवश्यकता है । (10 सदस्यों वाले समूह का औसत केवल 2 सदस्यों वाले समूह के औसत से अधिक होता है!)

यह काम करता है :

SELECT DISTINCT ON (perm, combo)
       perm
      ,combo
      ,avg(value)        OVER wpc AS perm_average_value
      ,avg(value)        OVER wc  AS combo_average_value
      ,stddev_pop(value) OVER wpc AS perm_stddev
      ,stddev_pop(value) OVER wc  AS combo_stddev
      ,count(*)          OVER wpc AS perm_count
      ,count(*)          OVER wc  AS combo_count
FROM   foo
WINDOW wc  AS (PARTITION BY combo)
      ,wpc AS (PARTITION BY perm, combo);

मैं यहां दो अलग-अलग विंडो का उपयोग कर रहा हूं, और उन पंक्तियों को कम कर रहा हूं DISTINCTजिनके साथ विंडो फ़ंक्शन के बाद भी लागू किया जाता है।

लेकिन मुझे गंभीरता से संदेह है कि यह आपकी मूल क्वेरी से अधिक तेज़ होगा। मुझे पूरा यकीन है कि यह नहीं है।

परिवर्तित तालिका लेआउट के साथ बेहतर प्रदर्शन

एरे के पास 24 बाइट्स का ओवरहेड है (प्रकार के आधार पर मामूली बदलाव)। इसके अलावा, आपको लगता है कि प्रति सरणी और कई पुनरावृत्तियों में कुछ आइटम हैं। आपकी तरह एक विशाल तालिका के लिए यह स्कीमा को सामान्य करने के लिए भुगतान करेगा । उदाहरण लेआउट:

CREATE TABLE combo ( 
  combo_id serial PRIMARY KEY
 ,combo    int[] NOT NULL
);

CREATE TABLE perm ( 
  perm_id  serial PRIMARY KEY
 ,perm     int[] NOT NULL
);

CREATE TABLE value (
  perm_id  int REFERENCES perm(perm_id)
 ,combo_id int REFERENCES combo(combo_id)
 ,value numeric NOT NULL DEFAULT 0
);

यदि आपको संदर्भात्मक अखंडता की आवश्यकता नहीं है, तो आप विदेशी कुंजी बाधाओं को छोड़ सकते हैं।

कनेक्शन को combo_idतालिका में भी रखा जा सकता है perm, लेकिन इस परिदृश्य में मैं इसे (थोड़ा सामान्यीकृत) valueबेहतर प्रदर्शन के लिए स्टोर करूंगा ।

इसका परिणाम 32 बाइट्स (टपल हेडर + पेडिंग: 24 बाइट्स, 2 एक्स इंट (8 बाइट), नो पैडिंग), और आपके numericकॉलम के अज्ञात आकार से होता है। (यदि आपको अत्यधिक सटीकता की आवश्यकता नहीं है, double precisionया एक realस्तंभ भी कर सकता है, तो)

SO या यहाँ इस संबंधित उत्तर में भौतिक संग्रहण पर अधिक :
पढ़ने के प्रदर्शन के लिए PostgreSQL को कॉन्फ़िगर करना

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

क्या तुम करोगी पहले एक सबक्वेरी में समग्र और उसके बाद के लिए शामिल होने permऔर comboबेहतरीन प्रदर्शन के लिए।


स्पष्ट और संक्षिप्त उत्तर के लिए धन्यवाद। आप सही हैं, ऐसा लगता है कि इस तरह से एक उप-जनसंख्या के मानक विचलन प्राप्त करने का कोई तरीका नहीं है। कहा जा रहा है, मुझे आपके समाधान की सरलता पसंद है। ग्रुप बाय को खत्म करने से परिणामी क्वेरी बहुत अधिक पठनीय हो जाती है। दुर्भाग्य से जैसा कि आपको संदेह था कि प्रदर्शन उप-समरूप है। मुझे 30 मिनट से अधिक समय तक चलने के बाद क्वेरी को मारना था।
स्कॉट स्मॉल

@ScottSmall: आप प्रदर्शन के लिए कुछ कर सकते हैं ... जवाब देने के लिए अपडेट देखें।
इरविन ब्रान्डस्टेट्टर

अपने प्रश्न को सरल बनाने के लिए, मैंने स्तंभों को उस fooतालिका से हटा दिया जो प्रासंगिक नहीं थी। वास्तव में, इस क्वेरी द्वारा उपयोग किए जाने वाले कई और कॉलम हैं, इसलिए मुझे यकीन नहीं है कि क्रमपरिवर्तन और संयोजनों को सामान्य करने से इस विशेष उपयोग के मामले में एक महत्वपूर्ण गति को बढ़ावा मिलेगा।
स्कॉट स्माल

इसके अलावा, प्रत्येक क्रमपरिवर्तन और संयोजन बनाने वाले पूर्णांक मान डीबी में एक अन्य तालिका से आते हैं। इस डेटा को प्री-जेनरेट करना कम्प्यूटेशनल रूप से महंगा है। एक परमिट / कॉम्बो की अधिकतम लंबाई 5 है, हालांकि 5Pn और 5Cn n के बड़े मूल्यों (वर्तमान में लगभग 1000, लेकिन दैनिक बढ़ते हुए) के लिए काफी बड़े होते हैं ... वैसे भी, अनुकूलन एक और दिन का सवाल है। आपकी सभी मदद के लिए फिर से धन्यवाद इरविन।
स्कॉट स्माल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.