PostgreSQL LIKE क्वेरी प्रदर्शन विविधताएँ


113

मैं LIKEअपने डेटाबेस में किसी विशेष तालिका में प्रश्नों के संबंध में प्रतिक्रिया समय में काफी बड़ी भिन्नता देख रहा हूं। कभी-कभी मुझे 200-400 एमएस (बहुत स्वीकार्य) के भीतर परिणाम मिलेंगे, लेकिन अन्य बार परिणाम वापस करने में 30 सेकंड तक का समय लग सकता है।

मैं समझता हूं कि LIKEप्रश्न बहुत ही गहन हैं, लेकिन मैं यह नहीं समझता कि प्रतिक्रिया के समय में इतना बड़ा अंतर क्यों होगा। मैंने owner1फ़ील्ड पर btree इंडेक्स बनाया है, लेकिन मुझे नहीं लगता कि यह LIKEप्रश्नों के साथ मदद करता है । क्या किसी के भी पास कोई सुझाव है?

नमूना SQL:

SELECT gid, owner1 FORM parcels
WHERE owner1 ILIKE '%someones name%' LIMIT 10

मैंने भी कोशिश की है:

SELECT gid, owner1 FROM parcels
WHERE lower(owner1) LIKE lower('%someones name%') LIMIT 10

तथा:

SELECT gid, owner1 FROM parcels
WHERE lower(owner1) LIKE lower('someones name%') LIMIT 10

समान परिणाम के साथ।
तालिका पंक्ति गणना: लगभग 95,000।

जवाबों:


284

FTS समर्थन नहीं करता है LIKE

पहले से स्वीकार किए जाते हैं जवाब गलत था। पूर्ण पाठ अनुक्रमणिका के साथ पूर्ण पाठ खोज ऑपरेटर के लिए बिल्कुल भी नहीं हैLIKE , इसके अपने ऑपरेटर हैं और यह मनमाने तार के लिए काम नहीं करता है। यह शब्दकोशों और उपजी के आधार पर शब्दों पर काम करता है। यह शब्दों के लिए उपसर्ग मिलान का समर्थन करता है , लेकिन ऑपरेटर के साथ नहीं :LIKE

के लिए ट्रिग्राम इंडेक्स LIKE

अतिरिक्त मॉड्यूल स्थापित करें pg_trgmजो सभी और पैटर्न का समर्थन करने के लिए GIN और GiST ट्रिग्राम इंडेक्स के लिए ऑपरेटर कक्षाएं प्रदान करता है , न केवल बाएं-लंगर वाले लोगों को:LIKEILIKE

उदाहरण सूचकांक:

CREATE INDEX tbl_col_gin_trgm_idx  ON tbl USING gin  (col gin_trgm_ops);

या:

CREATE INDEX tbl_col_gist_trgm_idx ON tbl USING gist (col gist_trgm_ops);

उदाहरण क्वेरी:

SELECT * FROM tbl WHERE col LIKE '%foo%';   -- leading wildcard
SELECT * FROM tbl WHERE col ILIKE '%foo%';  -- works case insensitively as well

Trigrams? छोटे तार के बारे में क्या?

अनुक्रमित मूल्यों में 3 से कम अक्षरों वाले शब्द अभी भी काम करते हैं। नियम पुस्तिका:

प्रत्येक शब्द को दो स्थानों को उपसर्ग माना जाता है और एक स्थान स्ट्रिंग में निहित त्रिकोण के सेट का निर्धारण करते समय प्रत्यय होता है।

और कम से कम 3 अक्षरों के साथ खोज पैटर्न? नियम पुस्तिका:

दोनों LIKEऔर नियमित-अभिव्यक्ति खोजों के लिए, ध्यान रखें कि बिना निकालने योग्य ट्रिगर्स वाला एक पैटर्न पूर्ण-सूचकांक स्कैन को पतित कर देगा।

मतलब, वह इंडेक्स / बिटमैप इंडेक्स स्कैन अभी भी काम करता है (तैयार स्टेटमेंट के लिए क्वेरी प्लान नहीं टूटेगा), यह आपको बेहतर प्रदर्शन नहीं देगा। आमतौर पर कोई बड़ा नुकसान नहीं होता है, क्योंकि 1- या 2-अक्षर तार शायद ही चयनात्मक होते हैं (अंतर्निहित टेबल मैचों के कुछ प्रतिशत से अधिक) और सूचकांक समर्थन के साथ प्रदर्शन में सुधार नहीं होगा, क्योंकि एक पूर्ण तालिका स्कैन तेज है।


text_pattern_ops उपसर्ग मिलान के लिए

केवल बाएं-लंगर वाले पैटर्न (कोई अग्रणी वाइल्डकार्ड) के लिए आपको btree इंडेक्स के लिए उपयुक्त ऑपरेटर वर्ग के साथ इष्टतम मिलता है : text_pattern_opsया varchar_pattern_ops। दोनों में निर्मित मानक Postgres की सुविधाएँ, कोई अतिरिक्त मॉड्यूल की आवश्यकता नहीं है। समान प्रदर्शन, लेकिन बहुत छोटे सूचकांक।

उदाहरण सूचकांक:

CREATE INDEX tbl_col_text_pattern_ops_idx ON tbl(col text_pattern_ops);

उदाहरण क्वेरी:

SELECT * FROM tbl WHERE col LIKE 'foo%';  -- no leading wildcard

या , यदि आपको अपना डेटाबेस loc C ’ लोकेल (प्रभावी रूप से कोई लोकेल) के साथ चलना चाहिए , तो सब कुछ बाइट ऑर्डर के अनुसार क्रमबद्ध हो जाता है और डिफॉल्ट ऑपरेटर क्लास वाला एक सादा btree इंडेक्स काम करता है।

Dba.SE पर इन संबंधित उत्तरों में अधिक विवरण, स्पष्टीकरण, उदाहरण और लिंक:


500K लाइनों की एक मेज पर कोई प्रमुख वाइल्डकार्ड के साथ, gin_trgm_ops साथ जिन सूचकांक 10 बार BTREE की तुलना में तेजी से किया जा रहा प्रतीत होता है
निकोलस

@nicolas: तुलना कई चरों पर निर्भर करती है। मुख्य लंबाई, डेटा वितरण, पैटर्न की लंबाई, संभव सूचकांक केवल स्कैन ... और सबसे महत्वपूर्ण: संस्करण को पोस्टग्रेट करता है। जीआई इंडेक्स को पीजी 9.4 और 9.5 में काफी सुधार किया गया है। Pg_trgm (pg 9.6 के साथ रिलीज़ होने वाला) का नया संस्करण और अधिक सुधार लाने जा रहा है।
इरविन ब्रान्डेसटेटर

1
अगर मुझे डॉक्स सही मिला, pg_trgmतो आपको कम से कम 3 अक्षरों की क्वेरी स्ट्रिंग की आवश्यकता होगी, उदाहरण के लिए fo%इंडेक्स हिट नहीं होगा , बल्कि एक स्कैन करें। नोट करने के लिए कुछ।
तुकाका मस्टोनन

1
@TuukkaMustonen: अच्छी बात है। खैर, (बिटमैप) इंडेक्स स्कैन अभी भी काम करते हैं , वे सिर्फ आपको बेहतर प्रदर्शन नहीं खरीदेंगे। मैंने ऊपर कुछ स्पष्टीकरण जोड़ा।
एरविन ब्रान्डस्टेट्टर

7

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

यदि आप फ़ील्ड के बीच में स्ट्रिंग की खोज करना चाहते हैं, तो आपको पूर्ण पाठ या ट्रायग्राम इंडेक्स में देखना चाहिए । उनमें से पहला पोस्टग्रेज कोर में है, दूसरा कंट्रिब मॉड्यूल में उपलब्ध है।


मैंने क्षेत्र के निचले मूल्य पर एक सूचकांक बनाने के बारे में नहीं सोचा था। इस तरह मैं क्वेरी पाठ को क्वेरी करने से पहले बैकएंड पर कम करने के लिए परिवर्तित कर सकता हूं।
जेसन

4

आप PostgreSQL में एक अलग प्रकार के इंडेक्स विल्द्स्पीड को स्थापित कर सकते हैं । Wildspeed% शब्द% वाइल्डकार्ड के साथ काम करता है, कोई समस्या नहीं है। नकारात्मक पक्ष सूचकांक का आकार है, यह बड़ा, बहुत बड़ा हो सकता है।


3

Postgresql में LIKE क्वेरी के प्रदर्शन को बेहतर बनाने के लिए कृपया नीचे उल्लेखित क्वेरी को निष्पादित करें। बड़ी तालिकाओं के लिए इस तरह एक सूचकांक बनाएं:

CREATE INDEX <indexname> ON <tablename> USING btree (<fieldname> text_pattern_ops)

यह केवल तभी काम करता है जब पैटर्न वाइल्डकार्ड के साथ शुरू नहीं होता है - इस मामले में पहले दो नमूना प्रश्न दोनों वाइल्डकार्ड से शुरू होते हैं।
cbz

1

क्या यह मूल्य के लिए है, Django ORM इसे असंवेदनशील बनाने के UPPER(text)लिए सभी LIKEप्रश्नों के लिए उपयोग करता है ,

UPPER(column::text)किसी भी अन्य चीज़ के विपरीत, एक इंडेक्स को जोड़ने से मेरे सिस्टम में काफी तेजी आई है।

जहाँ तक% अग्रणी है, हाँ जो एक सूचकांक का उपयोग नहीं करेगा। एक महान विवरण के लिए इस ब्लॉग को देखें:

https://use-the-index-luke.com/sql/where-clause/searching-for-ranges/like-performance-tuning


1

मेरे पास हाल ही में 200000 रिकॉर्ड वाली तालिका के साथ एक समान मुद्दा था और मुझे बार-बार LIKE क्वेरीज करने की आवश्यकता है। मेरे मामले में, खोज की जा रही स्ट्रिंग को ठीक किया गया था। अन्य क्षेत्र विविध। क्योंकि वह, मैं फिर से लिखने में सक्षम था:

SELECT owner1 FROM parcels
WHERE lower(owner1) LIKE lower('%someones name%');

जैसा

CREATE INDEX ix_parcels ON parcels(position(lower('someones name') in lower(owner1)));

SELECT owner1 FROM parcels
WHERE position(lower('someones name') in lower(owner1)) > 0;

मुझे खुशी हुई जब प्रश्न तेजी से वापस आए और सत्यापित किया गया कि सूचकांक का उपयोग किया जा रहा है EXPLAIN ANALYZE:

 Bitmap Heap Scan on parcels  (cost=7.66..25.59 rows=453 width=32) (actual time=0.006..0.006 rows=0 loops=1)
   Recheck Cond: ("position"(lower(owner1), 'someones name'::text) > 0)
   ->  Bitmap Index Scan on ix_parcels  (cost=0.00..7.55 rows=453 width=0) (actual time=0.004..0.004 rows=0 loops=1)
         Index Cond: ("position"(lower(owner1), 'someones name'::text) > 0)
 Planning time: 0.075 ms
 Execution time: 0.025 ms

0

आपके जैसे प्रश्न संभवतः आपके द्वारा बनाए गए अनुक्रमित का उपयोग नहीं कर सकते क्योंकि:

1) आपके LIKE मानदंड वाइल्डकार्ड से शुरू होते हैं।

2) आपने अपने LIKE मानदंड के साथ एक फ़ंक्शन का उपयोग किया है।


0

जब आप कभी किसी फ़ंक्शन जैसे LIKE, ILIKE, ऊपरी, निचले आदि स्तंभ पर एक क्लॉज़ का उपयोग करते हैं, तो वॉन्टेज आपके सामान्य इंडेक्स को ध्यान में नहीं रखते हैं। यह प्रत्येक पंक्ति के माध्यम से जाने वाली तालिका का पूर्ण स्कैन करेगा और इसलिए यह धीमा होगा।

सही तरीका यह होगा कि आप अपनी क्वेरी के अनुसार एक नया सूचकांक बनाएँ। उदाहरण के लिए अगर मैं केस सेंसिटिविटी के बिना किसी कॉलम का मिलान करना चाहता हूं और मेरा कॉलम एक वर्चर है। तब आप इसे इस तरह से कर सकते हैं।

create index ix_tblname_col_upper on tblname (UPPER(col) varchar_pattern_ops);

इसी तरह अगर आपका कॉलम एक टेक्स्ट है तो आप कुछ इस तरह से करते हैं

create index ix_tblname_col_upper on tblname (UPPER(col) text_pattern_ops);

इसी तरह आप फ़ंक्शन को अपने इच्छित किसी अन्य फ़ंक्शन के ऊपरी हिस्से में बदल सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.