यह संबंधपरक-विभाजन का मामला है। मैंने टैग जोड़ा।
सूचकांक
USER_PROPERTY_MAP(property_value_id, user_id)
पर PK या UNIQUE बाधा मानकर - इस क्रम में कॉलम मेरे प्रश्नों को तेज करने के लिए। संबंधित:
- क्या पहले फ़ील्ड पर प्रश्नों के लिए एक समग्र अनुक्रमणिका भी अच्छी है?
आपके पास PROPERTY_VALUE(value, property_name_id, id)
पर एक अनुक्रमणिका भी होनी चाहिए . फिर से, इस क्रम में कॉलम। अंतिम कॉलम जोड़ें id
केवल तभी जब आपको इसका केवल-अनुक्रमणीय स्कैन प्राप्त हो।
दी गई संपत्तियों की संख्या के लिए
इसे हल करने के कई तरीके हैं। यह बिल्कुल दो . के लिए सबसे सरल और तेज़ में से एक होना चाहिए गुण:
SELECT u.*
FROM users u
JOIN user_property_map up1 ON up1.user_id = u.id
JOIN user_property_map up2 USING (user_id)
WHERE up1.property_value_id =
(SELECT id FROM property_value WHERE property_name_id = 1 AND value = '101')
AND up2.property_value_id =
(SELECT id FROM property_value WHERE property_name_id = 2 AND value = '102')
-- AND u.user_name = 'user1' -- more filters?
-- AND u.city = 'city1'
टेबल पर नहीं जा रहे PROPERTY_NAME
, क्योंकि ऐसा लगता है कि आपने अपनी उदाहरण क्वेरी के अनुसार पहले से ही आईडी के लिए संपत्ति के नाम हल कर लिए हैं। नहीं तो आप PROPERTY_NAME
में एक जॉइन जोड़ सकते हैं प्रत्येक सबक्वेरी में।
हमने इस संबंधित प्रश्न के तहत तकनीकों का एक शस्त्रागार इकट्ठा किया है:
- एक हैस-मैनी-थ्रू संबंध में SQL परिणामों को कैसे फ़िल्टर करें
अज्ञात संख्या में प्रॉपर्टी के लिए
@Mike और @Valera के अपने-अपने उत्तरों में बहुत उपयोगी प्रश्न हैं। इसे और भी अधिक गतिशील बनाने के लिए :
WITH input(property_name_id, value) AS (
VALUES -- provide n rows with input parameters here
(1, '101')
, (2, '102')
-- more?
)
SELECT *
FROM users u
JOIN (
SELECT up.user_id AS id
FROM input
JOIN property_value pv USING (property_name_id, value)
JOIN user_property_map up ON up.property_value_id = pv.id
GROUP BY 1
HAVING count(*) = (SELECT count(*) FROM input)
) sub USING (id);
केवल VALUES
. से पंक्तियां जोड़ें/हटाएं अभिव्यक्ति। या WITH
हटा दें खंड और JOIN
कोई संपत्ति फ़िल्टर नहीं . के लिए बिल्कुल।
समस्या प्रश्नों के इस वर्ग के साथ (सभी आंशिक मिलानों की गणना करना) प्रदर्शन . है . मेरी पहली क्वेरी कम गतिशील है, लेकिन आम तौर पर काफी तेज है। (बस EXPLAIN ANALYZE
के साथ परीक्षण करें ।) विशेष रूप से बड़ी तालिकाओं और संपत्तियों की बढ़ती संख्या के लिए।
दोनों दुनिया के सर्वश्रेष्ठ?
पुनरावर्ती CTE वाला यह समाधान एक अच्छा समझौता होना चाहिए:तेज़ और गतिशील:
WITH RECURSIVE input AS (
SELECT count(*) OVER () AS ct
, row_number() OVER () AS rn
, *
FROM (
VALUES -- provide n rows with input parameters here
(1, '101')
, (2, '102')
-- more?
) i (property_name_id, value)
)
, rcte AS (
SELECT i.ct, i.rn, up.user_id AS id
FROM input i
JOIN property_value pv USING (property_name_id, value)
JOIN user_property_map up ON up.property_value_id = pv.id
WHERE i.rn = 1
UNION ALL
SELECT i.ct, i.rn, up.user_id
FROM rcte r
JOIN input i ON i.rn = r.rn + 1
JOIN property_value pv USING (property_name_id, value)
JOIN user_property_map up ON up.property_value_id = pv.id
AND up.user_id = r.id
)
SELECT u.*
FROM rcte r
JOIN users u USING (id)
WHERE r.ct = r.rn; -- has all matches
यहां dbfiddle
पुनरावर्ती सीटीई के बारे में मैनुअल।
अतिरिक्त जटिलता छोटी तालिकाओं के लिए भुगतान नहीं करती है जहां अतिरिक्त ओवरहेड किसी भी लाभ से अधिक है या अंतर शुरू करने के लिए नगण्य है। लेकिन यह बहुत बेहतर पैमाने पर है और बढ़ती तालिकाओं और संपत्ति फिल्टर की बढ़ती संख्या के साथ "गिनती" तकनीकों से बेहतर होता जा रहा है।
गिनती तकनीकों को सभी पर जाना होगा user_property_map
में पंक्तियां सभी दिए गए प्रॉपर्टी फ़िल्टर के लिए, जबकि यह क्वेरी (साथ ही पहली क्वेरी) अप्रासंगिक उपयोगकर्ताओं को जल्दी खत्म कर सकती है।
प्रदर्शन अनुकूलित करना
वर्तमान तालिका आँकड़ों के साथ (उचित सेटिंग्स, autovacuum
चल रहा है), पोस्टग्रेज़ को "सबसे सामान्य मूल्यों" . के बारे में जानकारी है प्रत्येक कॉलम में और पहली क्वेरी . में शामिल होने का क्रम बदलेगा पहले सबसे चुनिंदा प्रॉपर्टी फ़िल्टर का मूल्यांकन करने के लिए (या कम से कम चुनिंदा वाले नहीं)। एक निश्चित सीमा तक:join_collapse_limit
. संबंधित:
- Postgresql join_collapse_limit और क्वेरी प्लानिंग के लिए समय
- खोज शब्द में थोड़ा सा बदलाव क्वेरी को इतना धीमा क्यों कर देता है?
तीसरी क्वेरी के साथ यह "deus-ex-machina" हस्तक्षेप संभव नहीं है (पुनरावर्ती सीटीई)। प्रदर्शन में मदद करने के लिए (संभवतः बहुत अधिक) आपको पहले स्वयं अधिक चयनात्मक फ़िल्टर लगाने होंगे। लेकिन सबसे खराब स्थिति में भी यह गिनती के प्रश्नों से बेहतर प्रदर्शन करेगा।
संबंधित:
- पोस्टग्रेएसक्यूएल में आंकड़े लक्ष्य जांचें
बहुत अधिक रक्तरंजित विवरण:
- मौजूदा डेटा वाली तालिका में बनाए जाने पर PostgreSQL आंशिक अनुक्रमणिका अप्रयुक्त होती है
मैनुअल में अधिक स्पष्टीकरण:
- नियोजक द्वारा उपयोग किए गए आंकड़े