2012-06-28 20 views
99

मैं एक बहुत ही सरल SQL क्वेरी है:PostgreSQL COUNT (DISTINCT ...) बहुत धीमी गति से

SELECT COUNT(DISTINCT x) FROM table; 

मेरे मेज के बारे में 15 लाख पंक्तियां हैं। यह क्वेरी बहुत धीमी गति से चल रही है;

SELECT COUNT(x) FROM table; 

की तुलना में इसमें लगभग 7.535 लगते हैं, जिसमें लगभग 435ms लगते हैं। प्रदर्शन में सुधार के लिए मेरी क्वेरी बदलने का कोई तरीका है? मैंने समूहबद्ध करने और नियमित गणना करने की कोशिश की है, साथ ही एक्स पर एक इंडेक्स डालने की कोशिश की है; दोनों के पास 7.5 वें निष्पादन का समय है।

+0

मैं ऐसा नहीं सोचता:

SELECT COUNT(*) FROM (SELECT DISTINCT column_name FROM table_name) AS temp; 

यह बहुत तेजी से है। 1.5 मिलियन पंक्तियों के विशिष्ट मूल्य प्राप्त करना धीमा होने जा रहा है। – Ryan

+4

मैंने इसे सी # में आजमाया, स्मृति से 1.5 मिलियन * पूर्णांक के विशिष्ट मान प्राप्त करने * मेरे कंप्यूटर पर एक सेकंड से अधिक समय लेता है। तो मुझे लगता है कि आप शायद भाग्य से बाहर हैं। – Ryan

+0

क्वेरी प्लान टेबल संरचना (इंडेक्स) और ट्यूनिंग स्थिरांक (कार्य) मेम, प्रभावी_cache_size, random_page_cost) की सेटिंग पर निर्भर करेगा। उचित ट्यूनिंग के साथ क्वेरी को संभवतः एक सेकंड से भी कम समय में निष्पादित किया जा सकता है। – wildplasser

उत्तर

8
-- My default settings (this is basically a single-session machine, so work_mem is pretty high) 
SET effective_cache_size='2048MB'; 
SET work_mem='16MB'; 

\echo original 
EXPLAIN ANALYZE 
SELECT 
     COUNT (distinct val) as aantal 
FROM one 
     ; 

\echo group by+count(*) 
EXPLAIN ANALYZE 
SELECT 
     distinct val 
     -- , COUNT(*) 
FROM one 
GROUP BY val; 

\echo with CTE 
EXPLAIN ANALYZE 
WITH agg AS (
    SELECT distinct val 
    FROM one 
    GROUP BY val 
    ) 
SELECT COUNT (*) as aantal 
FROM agg 
     ; 

परिणाम:

original              QUERY PLAN              
---------------------------------------------------------------------------------------------------------------------- 
Aggregate (cost=36448.06..36448.07 rows=1 width=4) (actual time=1766.472..1766.472 rows=1 loops=1) 
    -> Seq Scan on one (cost=0.00..32698.45 rows=1499845 width=4) (actual time=31.371..185.914 rows=1499845 loops=1) 
Total runtime: 1766.642 ms 
(3 rows) 

group by+count(*) 
                 QUERY PLAN               
---------------------------------------------------------------------------------------------------------------------------- 
HashAggregate (cost=36464.31..36477.31 rows=1300 width=4) (actual time=412.470..412.598 rows=1300 loops=1) 
    -> HashAggregate (cost=36448.06..36461.06 rows=1300 width=4) (actual time=412.066..412.203 rows=1300 loops=1) 
     -> Seq Scan on one (cost=0.00..32698.45 rows=1499845 width=4) (actual time=26.134..166.846 rows=1499845 loops=1) 
Total runtime: 412.686 ms 
(4 rows) 

with CTE 
                  QUERY PLAN                
------------------------------------------------------------------------------------------------------------------------------------ 
Aggregate (cost=36506.56..36506.57 rows=1 width=0) (actual time=408.239..408.239 rows=1 loops=1) 
    CTE agg 
    -> HashAggregate (cost=36464.31..36477.31 rows=1300 width=4) (actual time=407.704..407.847 rows=1300 loops=1) 
      -> HashAggregate (cost=36448.06..36461.06 rows=1300 width=4) (actual time=407.320..407.467 rows=1300 loops=1) 
       -> Seq Scan on one (cost=0.00..32698.45 rows=1499845 width=4) (actual time=24.321..165.256 rows=1499845 loops=1) 
     -> CTE Scan on agg (cost=0.00..26.00 rows=1300 width=0) (actual time=407.707..408.154 rows=1300 loops=1) 
    Total runtime: 408.300 ms 
    (7 rows) 

CTE के लिए के रूप में ही योजना शायद भी अन्य विधियों (खिड़की कार्यों)

+2

क्या आपने कैशिंग का प्रभाव माना है? यदि तीनों बाद में "विश्लेषण का विश्लेषण करें" कर रहे हैं, तो पहला डिस्क डिस्क से चीजों को धीमा कर सकता है जबकि दोनों उत्तरार्द्ध स्मृति से तेजी से ला रहे हैं। – tobixen

+0

दरअसल: प्रभावी_cache_size ट्विक करने की पहली सेटिंग है। मेरा 2 जीबी, आईआईआरसी है। – wildplasser

+0

मैंने अपना प्रभावी_cache_size 2 जीबी तक सेट किया है, जिसमें प्रदर्शन में कोई बदलाव नहीं है। कोई अन्य सेटिंग्स जो आप सुझाव देना चाहते हैं? यदि हां, तो क्या? – ferson2020

1

द्वारा उत्पादित किया जा सकता है अपने count(distinct(x)) काफी count(x) धीमी गति से तो है आप कर सकते हैं अलग-अलग तालिका में एक्स मान गणना को बनाए रखकर इस क्वेरी को तेज करें, उदाहरण के लिए ट्रिगर्स का उपयोग करके table_name_x_counts (x integer not null, x_count int not null)। लेकिन आपका लेखन प्रदर्शन भुगतना होगा और यदि आप एकल लेनदेन में एकाधिक x मान अपडेट करते हैं तो आपको संभव डेडलॉक से बचने के लिए कुछ स्पष्ट क्रम में ऐसा करने की आवश्यकता होगी।

201

आप इस का उपयोग कर सकते हैं:

COUNT(DISTINCT column_name) 
+23

पवित्र प्रश्न बैटमैन! यह मेरी पोस्टग्रेस गिनती 1 9 0 से 4.5 तक 4.5 हो गई! – rogerdpack

+11

मुझे यह समझना अच्छा लगेगा कि यह क्यों काम करता है। महान टिप! – DavidMann10k

+11

मुझे यह धागा [www.postgresql.org] (http://www.postgresql.org) पर मिला जो एक ही बात पर चर्चा करता है: [लिंक] (http://www.postgresql.org/message-id/CAONnt+ [email protected])। उत्तरों में से एक (जेफ जेनेस द्वारा) का कहना है कि COUNT (DISTINCT()) हैश का उपयोग करने के बजाय टेबल को अपना काम करने के लिए टाइप करता है। – Ankur

संबंधित मुद्दे