कैसे अलग का चयन करने के लिए गति?


16

मेरे पास कुछ समय श्रृंखला डेटा पर एक सरल चयन विशिष्ट है:

SELECT DISTINCT user_id
FROM events
WHERE project_id = 6
AND time > '2015-01-11 8:00:00'
AND time < '2015-02-10 8:00:00';

और इसमें 112 सेकंड का समय लगता है। यहाँ क्वेरी योजना है:

http://explain.depesz.com/s/NTyA

मेरे आवेदन को इस तरह के कई अलग-अलग संचालन और मायने रखता है। क्या इस तरह का डेटा प्राप्त करने का एक तेज़ तरीका है?

जवाबों:


19

आप शायद यह नहीं सुनना चाहते, लेकिन सबसे अच्छा विकल्प SELECT DISTINCTयह है कि शुरुआत करने से बचें DISTINCT । कई मामलों में (सभी नहीं!) बेहतर डेटाबेस-डिज़ाइन या बेहतर प्रश्नों से बचा जा सकता है।

कभी-कभी, GROUP BYतेज, क्योंकि यह एक अलग कोड पथ लेता है।

में अपने विशेष मामले में, यह प्रतीत नहीं होता है कि आप से छुटकारा पा सकते DISTINCT। यदि आप उस तरह के कई प्रश्न हैं, तो आप एक विशेष सूचकांक के साथ क्वेरी का समर्थन कर सकते हैं:

CREATE INDEX foo ON events (project_id, "time", user_id);

जोड़ना user_idकेवल तभी उपयोगी है जब आपको इसमें से केवल-इंडेक्स मिले । विवरण के लिए लिंक का अनुसरण करें। अपने क्वेरी प्लान से महंगे बिटमैप हीप स्कैन को हटा देगा , जिसमें 90% क्वेरी समय की खपत होती है।

आपका EXPLAINआउटपुट मुझे बताता है कि क्वेरी को आधे मिलियन मिलान वाली पंक्तियों में से 2,491 विशिष्ट उपयोगकर्ताओं को संघनित करना है। यह सुपर-फास्ट नहीं बनेगा, चाहे आप कुछ भी करें, लेकिन यह काफी तेजी से हो सकता है।

यदि आपके प्रश्नों में समय अंतराल हमेशा समान होता है, तो प्रति MATERIALIIZED VIEWतह एक लंबा रास्ता तय करेगा। अलग-अलग समय अंतराल के साथ कोई मौका नहीं, हालांकि। हो सकता है कि आप प्रति घंटे या किसी अन्य न्यूनतम समय इकाई में कम से कम उपयोगकर्ताओं को मोड़ सकें, और जो कि पर्याप्त ओवरहेड वारंट के लिए पर्याप्त प्रदर्शन खरीदेंगे।user_id(project_id, <fixed time intervall>)

नाइटपिक:
सबसे अधिक संभव है, "time"वास्तव में भविष्यवाणी की जानी चाहिए:

AND "time" >= '2015-01-11 8:00:00'
AND "time" <  '2015-02-10 8:00:00';

एक तरफ: पहचानकर्ता के रूप में
उपयोग न करें time। यह मानक एसक्यूएल में एक आरक्षित शब्द है और पोस्टग्रेज में एक मूल प्रकार है।


मैंने इंडेक्स के बारे में थोड़ा पढ़ा है केवल स्कैन करता है, मैं इसे एक शॉट दूंगा।
सैम

दुर्भाग्य से, समय अंतराल तय नहीं है।
सैम

@ सलाम: सुझाव सूचकांक के साथ आपके उदाहरण क्वेरी को कितनी तेजी से मिला?
इरविन ब्रान्डस्टेट्टर

3
@edwin: अभी तक उत्पादन पर कोशिश नहीं की गई है। हालाँकि, मैंने अपने स्थानीय (उसी डेटा के साथ) पर मूल क्वेरी चलाई और इसमें 3678.780 एमएस लिया। फिर मैंने सूचकांक को जोड़ा और इसे 170.156 एमएस तक फैला दिया। अब योजना में 'इंडेक्स ओनली स्कैन ऑन फू यूज़ इन इवेंट्स' शामिल है।
सैम

1
@ शम: अच्छा! यही मेरा लक्ष्य था।
एरविन ब्रान्डस्टेट्टर

2

यहां सैम के मामले और इरविन के जवाब पर मेरा परीक्षण है

drop table t1
create table t1 (id int, user_id int, project_id int, date_time timestamp without time zone) ;

insert into t1 -- 10 million row - size="498 MB"
select row_number() over(), round(row_number() over()/1000), round(row_number() over()/100000) , date
from generate_series('2015-01-01'::date, '2016-12-01'::date,'6 seconds'::interval
) date 
limit 10000000

-- before indexing - 10000000 row - output=100 row - time=2900ms
SELECT DISTINCT user_id
FROM t1
WHERE project_id = 1
AND date_time > '2015-01-01 8:00:00'
AND date_time < '2016-12-01 8:00:00' ;

CREATE INDEX foo ON t1 (project_id, date_time, user_id); -- time process=51.2 secs -- size="387 MB"         

-- after indexing - 10000000 row - output=100 row - time= 75ms (reduce ~ 38 times)
SELECT DISTINCT user_id
FROM t1
WHERE project_id = 1
AND date_time > '2015-01-01 00:00:00'
AND date_time < '2016-12-01 00:00:00' ;

इरविन ने कहा, "आप शायद इसे सुनना नहीं चाहते हैं, लेकिन SELIST DISTINCT को गति देने का सबसे अच्छा विकल्प DISTINCT से बचने के लिए शुरू करना है। कई मामलों में (सभी नहीं!) इसे बेहतर डेटाबेस-डिज़ाइन या बेहतर प्रश्नों से बचा जा सकता है। ”। मुझे लगता है कि वह सही है, हमें "अलग-अलग, समूह द्वारा, आदेश द्वारा" (यदि कोई हो) का उपयोग करने से बचना चाहिए।

मैं सैम के मामले के रूप में एक स्थिति से मिला और मुझे लगता है कि सैम महीने तक इवेंट टेबल पर विभाजन का उपयोग कर सकता है। जब आप क्वेरी करेंगे तो यह आपके डेटा आकार को कम कर देगा, लेकिन आपको ऊपर क्वेरी के बजाय निष्पादित करने के लिए फ़ंक्शन (pl / pgsql) की आवश्यकता होगी। क्वेरी निष्पादित करने के लिए फ़ंक्शन उपयुक्त विभाजन (शर्तों पर निर्भर करता है) पाएगा।


2
> मुझे लगता है कि वह सही है, हमें "अलग, समूह द्वारा, क्रम से" का उपयोग करने से बचना चाहिए - और यह भी चुनें, INSERT और अद्यतन। यदि हम इन निर्माणों से बचते हैं, तो हमारा डेटाबेस बहुत तेज़ हो जाएगा!
महानोवैन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.