ठीक है, कम से कम सूचकांक का उपयोग किया जाता है। हालांकि, आपको सामान्य इंडेक्स स्कैन के बजाय बिटमैप इंडेक्स स्कैन मिलता है, जिसका अर्थ है कि xpath() फ़ंक्शन को कई बार कॉल किया जाएगा।
आइए एक छोटी सी जाँच करें:
CREATE TABLE foo ( id serial primary key, x xml, h hstore );
insert into foo (x,h) select XMLPARSE( CONTENT '<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<object_id>2</object_id>
<pack_form_id>' || n || '</pack_form_id>
<prod_form_id>34</prod_form_id>
</row>' ),
('object_id=>2,prod_form_id=>34,pack_form_id=>'||n)::hstore
FROM generate_series( 1,100000 ) n;
test=> EXPLAIN ANALYZE SELECT count(*) FROM foo;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
Aggregate (cost=4821.00..4821.01 rows=1 width=0) (actual time=24.694..24.694 rows=1 loops=1)
-> Seq Scan on foo (cost=0.00..4571.00 rows=100000 width=0) (actual time=0.006..13.996 rows=100000 loops=1)
Total runtime: 24.730 ms
test=> explain analyze select * from foo where (h->'pack_form_id')='123';
QUERY PLAN
----------------------------------------------------------------------------------------------------
Seq Scan on foo (cost=0.00..5571.00 rows=500 width=68) (actual time=0.075..48.763 rows=1 loops=1)
Filter: ((h -> 'pack_form_id'::text) = '123'::text)
Total runtime: 36.808 ms
test=> explain analyze select * from foo where ((xpath('//pack_form_id/text()'::text, x))[1]::text) = '123';
QUERY PLAN
------------------------------------------------------------------------------------------------------
Seq Scan on foo (cost=0.00..5071.00 rows=500 width=68) (actual time=4.271..3368.838 rows=1 loops=1)
Filter: (((xpath('//pack_form_id/text()'::text, x, '{}'::text[]))[1])::text = '123'::text)
Total runtime: 3368.865 ms
जैसा कि हम देख सकते हैं,
- संपूर्ण तालिका को गिनती (*) के साथ स्कैन करने में 25 एमएस लगते हैं
- एक स्टोर से एक कुंजी/मान निकालने से एक छोटी अतिरिक्त लागत जुड़ जाती है, लगभग 0.12 μs/पंक्ति
- xpath का उपयोग करके किसी xml से एक कुंजी/मान निकालने से एक बड़ी लागत जुड़ जाती है, लगभग 33 µs/पंक्ति
निष्कर्ष :
- xml धीमा है (लेकिन यह सभी जानते हैं)
- यदि आप किसी कॉलम में एक फ्लेक्सिबल की/वैल्यू स्टोर रखना चाहते हैं, तो hstore का उपयोग करें
चूंकि आपका एक्सएमएल डेटा बहुत बड़ा है, इसलिए इसे टोस्ट किया जाएगा (संपीड़ित और मुख्य तालिका से बाहर संग्रहीत)। इससे मुख्य तालिका में पंक्तियाँ बहुत छोटी हो जाती हैं, इसलिए प्रति पृष्ठ अधिक पंक्तियाँ, जो बिटमैप स्कैन की दक्षता को कम कर देती हैं क्योंकि किसी पृष्ठ की सभी पंक्तियों को फिर से जाँचना पड़ता है।
हालांकि आप इसे ठीक कर सकते हैं। किसी कारण से xpath() फ़ंक्शन (जो बहुत धीमा है, क्योंकि यह xml को संभालता है) की लागत समान (1 इकाई) है, जैसे कि पूर्णांक ऑपरेटर "+"...
update pg_proc set procost=1000 where proname='xpath';
आपको लागत मूल्य में बदलाव करने की आवश्यकता हो सकती है। जब सही जानकारी दी जाती है, तो योजनाकार जानता है कि xpath धीमा है और इसके बजाय एक इंडेक्स स्कैन का उपयोग करके बिटमैप इंडेक्स स्कैन से बच जाएगा, जिसके लिए किसी पृष्ठ पर सभी पंक्तियों के लिए स्थिति को फिर से जांचने की आवश्यकता नहीं होती है।
ध्यान दें कि यह पंक्ति अनुमान समस्या का समाधान नहीं करता है। चूंकि आप xml (या hstore) के अंदर का विश्लेषण नहीं कर सकते हैं, इसलिए आपको पंक्तियों की संख्या (यहां, 500) के लिए डिफ़ॉल्ट अनुमान मिलते हैं। तो, योजनाकार पूरी तरह से गलत हो सकता है और कुछ शामिल होने पर एक विनाशकारी योजना चुन सकता है। इसका एकमात्र समाधान उचित स्तंभों का उपयोग करना है।