6

के लिए गिनती क्वेरी का अनुकूलन मेरे पास postgresql में एक सारणी है जिसमें एक सरणी है जो लगातार अद्यतन होती है।PostgreSQL

मेरे आवेदन में मुझे पंक्तियों की संख्या प्राप्त करने की आवश्यकता है जिसके लिए उस सरणी कॉलम में एक विशिष्ट पैरामीटर मौजूद नहीं है। मेरे क्वेरी इस तरह दिखता है:

select count(id) 
from table 
where not (ARRAY['parameter value'] <@ table.array_column) 

लेकिन जब पंक्तियों की राशि और उस क्वेरी के लिए सजा की मात्रा प्रति सेकंड (कई बार, संभवतः सैकड़ों या हजारों) प्रदर्शन एक बहुत decreses बढ़ रही है, यह है कि मुझे लगता है postgresql में गिनती निष्पादन का एक रैखिक क्रम हो सकता है (मुझे इस बारे में पूरी तरह से यकीन नहीं है)।

मूल रूप से मेरे सवाल है:

वहाँ एक मौजूदा पैटर्न मैं उस के बारे में पता नहीं कर रहा हूँ लागू होता है इस स्थिति के लिए? इसके लिए सबसे अच्छा तरीका क्या होगा?

कोई भी सुझाव जो आप मुझे दे सकते हैं वास्तव में सराहना की जाएगी।

+0

यकीन नहीं है, लेकिन मुझे लगता है कि table.array_column पर एक जीआईएन इंडेक्स इसे गति देने में मदद करेगा। पता लगाने के लिए आपको एक्स्पलाइन चलाने की आवश्यकता होगी। यहां देखें: http://dba.stackexchange.com/a/27505/1822 –

+1

पोस्टग्रेस में यह कुशल बनाना मुश्किल होगा क्योंकि तालिका बड़ी हो जाती है। एक जीन इंडेक्स केवल तभी मदद करेगा जब "निहित" के परीक्षण के रूप में आपके भविष्य में "निहित नहीं" के विपरीत। यदि यह महत्वपूर्ण नहीं है कि गणना 100% सटीक हो, तो आप इसे कुछ टीटीएल के साथ ऐप परत पर कैशिंग करने का प्रयास कर सकते हैं। यदि तालिका पर आपकी लेखन दर बहुत अधिक नहीं है, तो आप वर्तमान गणना वाले किसी अन्य तालिका को अपडेट करने के लिए ट्रिगर का उपयोग कर सकते हैं। – dbenhur

+0

अपना संस्करण दिखाने के लिए सर्वश्रेष्ठ और 'विश्लेषण की व्याख्या करें'; http://stackoverflow.com/tags/postgresql-performance/info –

उत्तर

2

क्या कोई मौजूदा पैटर्न है जो मुझे पता नहीं है कि इस स्थिति पर लागू होता है? इसके लिए सबसे अच्छा तरीका क्या होगा?

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

CREATE TABLE demo(id integer primary key); 
INSERT INTO demo (id) SELECT id FROM arrtable; 
CREATE TABLE properties (
    demo_id integer not null references demo(id), 
    property integer not null, 
    primary key (demo_id, property) 
); 
CREATE INDEX properties_property_idx ON properties(property); 

फिर आप गुण क्वेरी कर सकते हैं:

SELECT count(id) 
FROM demo 
WHERE NOT EXISTS (
    SELECT 1 FROM properties WHERE demo.id = properties.demo_id AND property = 1 
) 

मैं इस उम्मीद बहुत तेजी से मूल प्रश्न से हो सकता है, लेकिन यह वास्तव में बहुत ही नमूना डेटा के साथ एक ही है; यह आपकी मूल क्वेरी के समान 2s से 3s रेंज में चलता है। यह वही मुद्दा है जहां के लिए खोज रहे हैं क्या है, इसकी खोज करने से बहुत धीमी है; अगर हम संपत्ति वाले पंक्तियों की तलाश में हैं तो हम demo के seqscan से बच सकते हैं और आईडी से मेल खाने के लिए केवल properties स्कैन कर सकते हैं।

फिर, सरणी युक्त तालिका पर एक सीक स्कैन नौकरी भी करता है।

+0

उस विस्तृत स्पष्टीकरण के लिए धन्यवाद, हाँ, मेरी वर्तमान स्थिति में स्पष्ट रूप से अनुक्रमिक गिनती करना या खोज को तेज़ी से बनाने के लिए जानकारी को स्टोर करने के किसी अन्य तरीके के बारे में सोचना बेहतर है, फिर भी बहुत धन्यवाद यह वास्तव में उपयोगी रहा है – jeruki

2

मुझे लगता है कि आपके वर्तमान डेटा मॉडल के साथ आप भाग्य से बाहर हैं। एक एल्गोरिदम के बारे में सोचने का प्रयास करें कि डेटाबेस को आपकी क्वेरी के लिए निष्पादित करना है। डेटा की अनुक्रमिक स्कैनिंग के बिना यह कोई रास्ता नहीं हो सकता है।

क्या आप कॉलम व्यवस्थित कर सकते हैं ताकि यह डेटा के विपरीत को स्टोर कर सके (ताकि क्वेरी select count(id) from table where ARRAY[‘parameter value’] <@ table.array_column हो)? यह क्वेरी एक जीन/गिस्ट इंडेक्स का उपयोग करेगी।

5

पोस्टग्रेएसक्यूएल वास्तव में सरणी कॉलम पर जीआईएन इंडेक्स का समर्थन करता है। दुर्भाग्यवश, यह NOT ARRAY[...] <@ indexed_col के लिए उपयोग करने योग्य प्रतीत नहीं होता है, और GIN अनुक्रमणिका अक्सर-अद्यतन तालिकाओं के लिए अनुपयुक्त हैं।

डेमो:

CREATE TABLE arrtable (id integer primary key, array_column integer[]); 

INSERT INTO arrtable(1, ARRAY[1,2,3,4]); 

CREATE INDEX arrtable_arraycolumn_gin_arr_idx 
ON arrtable USING GIN(array_column); 

-- Use the following *only* for testing whether Pg can use an index 
-- Do not use it in production. 
SET enable_seqscan = off; 

explain (buffers, analyze) select count(id) 
from arrtable 
where not (ARRAY[1] <@ arrtable.array_column); 

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

आप प्रविष्टियों को गिनने के लिए इंडेक्स का उपयोग कर सकते हैं में लक्ष्य मान होता है, फिर उस प्रविष्टि को सभी प्रविष्टियों की गणना से घटाएं। चूंकि count आईएनजी तालिका में सभी पंक्तियां PostgreSQL (9.1 और पुराने) में काफी धीमी है और अनुक्रमिक स्कैन की आवश्यकता है, यह वास्तव में आपकी वर्तमान क्वेरी से धीमी होगी। यह संभव है कि 9.2 पर एक सूचकांक-केवल स्कैन पंक्तियों गिनती करने के लिए इस्तेमाल किया जा सकता है कि अगर आप id पर एक बी पेड़ सूचकांक, जिस स्थिति में यह वास्तव में ठीक हो सकता है है:

SELECT (
    SELECT count(id) FROM arrtable 
) - (
    SELECT count(id) FROM arrtable 
    WHERE (ARRAY[1] <@ arrtable.array_column) 
); 

यह से भी बदतर प्रदर्शन करने के लिए गारंटी है पीजी 9.1 और उसके बाद के लिए आपका मूल संस्करण, क्योंकि seqscan के अतिरिक्त आपके मूल को भी को एक जीआईएन इंडेक्स स्कैन की आवश्यकता है। मैंने अब 9.2 पर इसका परीक्षण किया है और यह गिनती के लिए एक इंडेक्स का उपयोग करने लगता है, इसलिए 9.2 के लिए खोज करना उचित है।

drop index arrtable_arraycolumn_gin_arr_idx ; 
truncate table arrtable; 
insert into arrtable (id, array_column) 
select s, ARRAY[1,2,s,s*2,s*3,s/2,s/4] FROM generate_series(1,1000000) s; 
CREATE INDEX arrtable_arraycolumn_gin_arr_idx 
ON arrtable USING GIN(array_column); 

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

बदतर, इस इंडेक्स का उपयोग करने वाली क्वेरी आपके मूल क्वेरी के रूप में दो गुना तक और उसी डेटा सेट पर तक आधे से अधिक समय तक ले जाती है। यह उन मामलों के लिए सबसे खराब है जहां सूचकांक ARRAY[1] - 4s बनाम 2s मूल क्वेरी के लिए बहुत चुनिंदा नहीं है। जहां सूचकांक अत्यधिक चुनिंदा है (यानी: ARRAY[199] जैसे कई मैचों नहीं) यह मूल के 3s बनाम लगभग 1.2 सेकंड में चलता है। यह सूचकांक इस क्वेरी के लिए बस लायक नहीं है।

यहां सबक? कभी-कभी, सही उत्तर केवल अनुक्रमिक स्कैन करना है।

कि चूंकि अपने हिट दरों के लिए करना होगा नहीं, या तो एक ट्रिगर के साथ एक materialized दृश्य को बनाए रखने के @debenhur के रूप में पता चलता है, या सरणी को उलटने के लिए मानकों को प्रवेश करता है कि नहीं तो आप की एक सूची बनने की कोशिश एक जीआईएसटी इंडेक्स का उपयोग @maniek के रूप में कर सकता है।