2009-09-23 15 views
9

क्या पोस्टग्रेज़ में एक विशिष्ट जॉइन ऑर्डर को मजबूर करने का कोई तरीका है?पोस्टग्रेज़ में तालिका में शामिल होने के लिए

मुझे एक ऐसा प्रश्न है जो इस तरह दिखता है। मैंने वास्तविक सामग्री में मौजूद सामानों का एक गुच्छा समाप्त कर दिया है, लेकिन यह सरलीकरण इस मुद्दे को प्रदर्शित करता है। जो बचा है वह बहुत ही गूढ़ नहीं होना चाहिए: भूमिका/कार्य सुरक्षा प्रणाली का उपयोग करके, मैं यह निर्धारित करने की कोशिश कर रहा हूं कि किसी दिए गए उपयोगकर्ता को दिए गए कार्य को करने के लिए विशेषाधिकार हैं या नहीं।

select task.taskid 
from userlogin 
join userrole using (userloginid) 
join roletask using (roleid) 
join task using (taskid) 
where loginname='foobar' 
and taskfunction='plugh' 

लेकिन मैंने महसूस किया कि कार्यक्रम पहले से ही USERLOGIN का मूल्य जानता है, तो यह USERLOGIN पर देखने को छोड़ने और सिर्फ userloginid भरते हुए, इस तरह से लग रहा था क्वेरी और अधिक कुशल बनाया जा सकता है:

select task.taskid 
from userrole 
join roletask using (roleid) 
join task using (taskid) 
where userloginid=42 
and taskfunction='plugh' 

जब मैंने ऐसा किया - क्वेरी से एक तालिका को समाप्त करना और उस तालिका से पुनर्प्राप्त मूल्य को हार्ड-कोडिंग करना - समझाया गया योजना का समय बढ़ गया! मूल क्वेरी में, पोस्टग्रेज़ उपयोगकर्ता लॉगिन को पढ़ते हैं, फिर userrole तो फिर कार्यलेट roletask। लेकिन नई पूछताछ में, उसने पहले roletask पढ़ने का फैसला किया, और उसके बाद userrole में शामिल हो गए, भले ही इसे roletask पर एक पूर्ण फ़ाइल स्कैन करने की आवश्यकता हो।

पूर्ण समझाने की योजना है:

संस्करण 1:

Hash Join (cost=12.79..140.82 rows=1 width=8) 
    Hash Cond: (roletask.taskid = task.taskid) 
    -> Nested Loop (cost=4.51..129.73 rows=748 width=8) 
     -> Nested Loop (cost=4.51..101.09 rows=12 width=8) 
       -> Index Scan using idx_userlogin_loginname on userlogin (cost=0.00..8.27 rows=1 width=8) 
        Index Cond: ((loginname)::text = 'foobar'::text) 
       -> Bitmap Heap Scan on userrole (cost=4.51..92.41 rows=33 width=16) 
        Recheck Cond: (userrole.userloginid = userlogin.userloginid) 
        -> Bitmap Index Scan on idx_userrole_login (cost=0.00..4.50 rows=33 width=0) 
          Index Cond: (userrole.userloginid = userlogin.userloginid) 
     -> Index Scan using idx_roletask_role on roletask (cost=0.00..1.50 rows=71 width=16) 
       Index Cond: (roletask.roleid = userrole.roleid) 
    -> Hash (cost=8.27..8.27 rows=1 width=8) 
     -> Index Scan using idx_task_taskfunction on task (cost=0.00..8.27 rows=1 width=8) 
       Index Cond: ((taskfunction)::text = 'plugh'::text) 

संस्करण 2:

Hash Join (cost=96.58..192.82 rows=4 width=8) 
    Hash Cond: (roletask.roleid = userrole.roleid) 
    -> Hash Join (cost=8.28..104.10 rows=9 width=16) 
     Hash Cond: (roletask.taskid = task.taskid) 
     -> Seq Scan on roletask (cost=0.00..78.35 rows=4635 width=16) 
     -> Hash (cost=8.27..8.27 rows=1 width=8) 
       -> Index Scan using idx_task_taskfunction on task (cost=0.00..8.27 rows=1 width=8) 
        Index Cond: ((taskfunction)::text = 'plugh'::text) 
    -> Hash (cost=87.92..87.92 rows=31 width=8) 
     -> Bitmap Heap Scan on userrole (cost=4.49..87.92 rows=31 width=8) 
       Recheck Cond: (userloginid = 42) 
       -> Bitmap Index Scan on idx_userrole_login (cost=0.00..4.49 rows=31 width=0) 
        Index Cond: (userloginid = 42) 

(हाँ, मुझे पता है कि दोनों ही मामलों में लागत कम है और अंतर नहीं करता है कि ऐसा लगता है कि इससे कोई फर्क नहीं पड़ता। लेकिन यह है कि मैंने जो पोस्ट करना है उसे सरल बनाने के लिए क्वेरी से अतिरिक्त काम का एक गुच्छा समाप्त कर दिया। असली सवाल अभी भी अपमानजनक नहीं है, लेकिन मुझे टी में अधिक दिलचस्पी है । वह सिद्धांत)

+2

क्या आप क्वेरी योजनाएं (विश्लेषण समझाएं) और तालिका परिभाषाएं दिखा सकते हैं? – hgmnz

+0

ठीक है, आपने पूछा, मैंने वास्तविक क्वेरी के साथ काल्पनिक सरल उदाहरण को प्रतिस्थापित किया, और योजना परिणामों को समझाया। ओह, मुझे यकीन है कि मैं दूसरी क्वेरी को तेज करने के लिए कुछ अतिरिक्त इंडेक्स जोड़ सकता हूं, लेकिन यह बात नहीं है। पोस्टग्रेस ने ऐसी योजना क्यों चुनी जो कि सबसे अच्छा था, जो कि यह कर सकता था, उसके प्रश्नों के मुताबिक? खासकर जब यह दिखाया गया कि अगर मैं क्वेरी को अधिक जटिल बना देता तो बेहतर हो सकता है? – Jay

+0

क्या आप प्रश्नों के वास्तविक रन समय की तुलना कर रहे हैं या सिर्फ व्याख्या योजना में शीर्षक लागत देख रहे हैं? मूल्य? विशेष रूप से, आपने अभी विश्लेषण की व्याख्या नहीं की है, आउटपुट समझाया है। यद्यपि आप एक धीमी क्वेरी चलाने के बराबर उच्च लागत की अपेक्षा करेंगे, यह शायद इस तरह से काम न करे। – araqnid

उत्तर

4

दस्तावेज में यह पृष्ठ बताता है कि कैसे आप अपने आप को नियंत्रित करने के लिए मिलती है की अनुमति देता है में शामिल हो गए तालिकाओं को पुन: क्रम से PostgreSQL अनुकूलक को रोकने के लिए,:

http://www.postgresql.org/docs/current/interactive/explicit-joins.html

+1

PostgreSQL में वास्तव में एक आरडीबीएमएस के सर्वोत्तम दस्तावेज हैं जो मैंने देखा है। – hgmnz

+1

क्या आपने यह कोशिश की है? मैं निश्चित रूप से यहां और एक या दो के लिए, सभी प्रश्नों के लिए इस सेटिंग को बदलना नहीं चाहता हूं। यदि मैं इसे एक सेट स्टेटमेंट के साथ बदलता हूं, तो क्या यह पूरे डेटाबेस इंजन, या केवल वर्तमान कनेक्शन, या वर्तमान लेनदेन को प्रभावित करता है? हम्म, मुझे लगता है कि मैं इसे दो कनेक्शन खोलकर, इसे एक से सेट करके, और फिर देख सकता हूं कि दूसरे परिवर्तन पर योजनाओं की व्याख्या करें ... – Jay

+0

मैंने इसे आजमाया नहीं है। आप सही हैं कि समवर्ती सत्रों की एक जोड़ी में स्वयं को आजमाने का यह सुनिश्चित करने का सबसे अच्छा तरीका है। डॉक्टर गलत हो सकता है (हालांकि @ggiminez बताता है, शायद ही कभी PostgreSQL के दस्तावेज़ में)। –

1

आप सुनिश्चित करें कि आपके तालिका आंकड़े हैं अद्यतित हैं? जब PostgreSQLs लागत आधारित अनुकूलक ऐसी छोटी चीजों के साथ विफल रहता है तो यह एक बहुत अच्छा संकेत है तालिका तालिका के साथ कुछ गंभीरता से गलत है। अंतर्निहित ऑप्टिमाइज़र को ओवरराइड करके इसके आसपास काम करने के बजाय मूल कारण को ठीक करना बेहतर है क्योंकि समस्या अनिवार्य रूप से कहीं और भी पॉप अप हो जाएगी।

प्रभावित टेबल पर ANALYZE चलाएं और देखें कि क्या यह PostgreSQL को एक अलग योजना चुनता है या नहीं। अगर यह अभी भी मूर्खतापूर्ण चुनता है तो क्वेरी योजनाओं को देखना वाकई दिलचस्प होगा। ऑप्टिमाइज़र सही चीज़ नहीं कर रहा है आमतौर पर एक बग माना जाता है।

+0

हां। मेरे प्रारंभिक आश्चर्यजनक परिणामों के बाद, मैंने उन तालिकाओं पर विश्लेषण फिर से चलाया और फिर समझाया योजनाओं को फिर से किया, और परिणाम समान थे। – Jay

+1

यह थोड़ा अजीब लगता है। आपकी प्रभावी_cache_size सेटिंग क्या है? डिफ़ॉल्ट 128 एम छोटे से मध्यम तालिकाओं पर अनुचित अनुक्रमिक स्कैन का कारण बन सकता है। इसके अलावा, random_page_cost को कम करने वाले भारी कैश किए गए डेटाबेस के लिए एक अच्छा विचार हो सकता है। –

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