क्यों?
क्वेरी प्रिंसिपल पर इंडेक्स का उपयोग नहीं कर सकती है। आपको तालिका locations . पर एक अनुक्रमणिका की आवश्यकता होगी , लेकिन आपके पास टेबल पर है addresses ।
आप सेटिंग करके मेरे दावे की पुष्टि कर सकते हैं:
SET enable_seqscan = off;
(केवल आपके सत्र में, और केवल डिबगिंग के लिए। इसे उत्पादन में कभी भी उपयोग न करें।) ऐसा नहीं है कि अनुक्रमिक स्कैन की तुलना में अनुक्रमणिका अधिक महंगी होगी, पोस्टग्रेज़ के लिए इसे आपकी क्वेरी के लिए उपयोग करने का कोई तरीका नहीं है बिल्कुल भी ।
इसके अलावा:[INNER] JOIN ... ON true यह कहने का एक अजीब तरीका है CROSS JOIN ...
ORDER को हटाने के बाद इंडेक्स का इस्तेमाल क्यों किया जाता है? और LIMIT ?
क्योंकि Postgres इस सरल फ़ॉर्म को फिर से लिख सकते हैं:
SELECT *
FROM addresses a
JOIN locations l ON a.address ILIKE '%' || l.postalcode || '%';
आपको ठीक वही क्वेरी योजना दिखाई देगी. (कम से कम मैं पोस्टग्रेज 9.5 पर अपने परीक्षणों में करता हूं।)
समाधान
आपको locations.postalcode . पर एक इंडेक्स चाहिए . और LIKE . का उपयोग करते समय या ILIKE आपको अनुक्रमित अभिव्यक्ति भी लाने की आवश्यकता होगी (postalcode ) बाएं ऑपरेटर की तरफ। ILIKE ऑपरेटर के साथ कार्यान्वित किया जाता है ~~* और इस ऑपरेटर के पास कोई COMMUTATOR नहीं है (एक तार्किक आवश्यकता), इसलिए ऑपरेंड को इधर-उधर करना संभव नहीं है। इन संबंधित उत्तरों में विस्तृत विवरण:
- क्या PostgreSQL इंडेक्स ऐरे कॉलम कर सकता है?ए>
- PostgreSQL - text Array के समान मान है
- क्या रेगेक्स पैटर्न वाले टेक्स्ट कॉलम को उपयोगी रूप से अनुक्रमित करने का कोई तरीका है?
एक समाधान ट्रिग्राम समानता ऑपरेटर %
या इसका उलटा, डिस्टेंस ऑपरेटर <->
एक निकटतम पड़ोसी . में इसके बजाय क्वेरी (प्रत्येक स्वयं के लिए कम्यूटेटर है, इसलिए ऑपरेंड स्वतंत्र रूप से स्थान बदल सकते हैं):
SELECT *
FROM addresses a
JOIN LATERAL (
SELECT *
FROM locations
ORDER BY postalcode <-> a.address
LIMIT 1
) l ON address ILIKE '%' || postalcode || '%';
सबसे समान postalcode खोजें प्रत्येक address . के लिए , और फिर जांचें कि क्या वह postalcode . है वास्तव में पूरी तरह से मेल खाता है।
इस तरह, एक लंबा postalcode स्वचालित रूप से पसंद किया जाएगा क्योंकि यह छोटे postalcode . की तुलना में अधिक समान (छोटी दूरी) है वह भी मेल खाता है।
थोड़ी अनिश्चितता बनी हुई है। संभावित पोस्टल कोड के आधार पर, स्ट्रिंग के अन्य भागों में ट्रिगर मिलान के कारण झूठी सकारात्मकता हो सकती है। अधिक कहने के लिए प्रश्न में पर्याप्त जानकारी नहीं है।
यहां , [INNER] JOIN CROSS JOIN . के बजाय समझ में आता है, क्योंकि हम एक वास्तविक शामिल होने की शर्त जोड़ते हैं।
तो:
CREATE INDEX locations_postalcode_trgm_gist_idx ON locations
USING gist (postalcode gist_trgm_ops);