PostGIS दूरी प्रश्नों के लिए इंडेक्स को ठीक से कैसे सेट करें?


18

मैं एक ऐसे एप्लिकेशन का निर्माण कर रहा हूं, जिसे क्वेरी करना है और हर Recordउस तालिका में लौटना है जो इससे Xकिलोमीटर दूर है PointXRecordsऔर PointXपदों से निर्धारित कर रहे हैं(long/lat) Google Geocode API द्वारा प्रदान की गई जानकारी जाती है।

मैं PostGIS के लिए नया हूं। एक त्वरित शोध के बाद, मुझे यह प्रश्न मिला है । उत्तर की तर्ज पर लगता है:

SELECT *
FROM your_table
WHERE ST_Distance_Sphere(the_geom, ST_MakePoint(your_lon,your_lat)) <= radius_mi * 1609.34

समस्या यह है: भले ही मैं केवल जीआईएस पर शुरू कर रहा हूं, जब मैं उपरोक्त क्वेरी को देखता हूं, तो मैं संभवतः कल्पना नहीं कर सकता कि यह कैसे एक सूचकांक का उपयोग कर सकता है। 2 फ़ंक्शन कॉल हैं। मैं कल्पना करता हूं कि टेबल हर के लिए स्कैन की जा रही है Record। मैं गलत होना चाहता हूँ :)

प्रश्न: क्या PostGIS में कोई भी सूचकांक प्रकार है जो उपरोक्त क्वेरी करने वाले को बनाने में सक्षम है? यदि नहीं, तो अनुशंसित तरीका क्या होगा जो मुझे चाहिए?


सुनिश्चित करें कि आप सही सूचकांक का निर्माण, भूगोल के लिए एक डाली पर, और एक लागू होते हैं ST_SetSRID()करने के लिए ST_MakePointक्वेरी में भूगोल के लिए कास्टिंग से पहले।
विन्स

जवाबों:


38

geometryWGS 1984 भौगोलिक डेटा (SRID 4326) का उपयोग करते हुए स्तंभों के साथ बड़े तालिकाओं के साथ अच्छा जियोडेटिक क्वेरी प्रदर्शन प्राप्त करने के लिए दो कुंजी हैं :

  1. उपयोग ST_DWithinफ़ंक्शन का , जो एक उपलब्ध स्थानिक इंडेक्स का उपयोग करके खोज करता है, और एक कार्टेशियन दूरी के साथ भूगोल सुविधाओं को ढूंढेगा
  2. भूगोल कास्ट पर एक अतिरिक्त इंडेक्स बनाएं, ताकि ST_DWithinइसका उपयोग कर सकें

तो आइए देखें कि असल दुनिया में क्या होता है। पहले हमें एक मिलियन यादृच्छिक बिंदुओं की तालिका बनाने और आबाद करने की आवश्यकता है:

DROP TABLE IF EXISTS example1
;

CREATE TABLE example1 (
    idcol   serial      NOT NULL,
    geomcol geometry        NULL,
    CONSTRAINT  example1_pk PRIMARY KEY (idcol),
    CONSTRAINT  enforce_srid CHECK (st_srid(geomcol) = 4326)
)
with (
    OIDS=FALSE
);

INSERT INTO example1(geomcol)
SELECT  ST_SetSRID(
            ST_MakePoint(
            (random()*360.0) - 180.0,
            (acos(1.0 - 2.0 * random()) * 2.0 - pi()) * 90.0 / pi()),
            4326) as geomcol
FROM  generate_series(1, 1000000) vtab;

CREATE INDEX example1_spx ON example1 USING GIST (geomcol);
-- (took about 22 sec)

यदि हम ST_Distance क्वेरी निष्पादित करते हैं, तो हमें आपकी अपेक्षित पूर्ण तालिका स्कैन मिल जाएगी:

EXPLAIN ANALYZE VERBOSE
SELECT  count(*)
FROM    example1
WHERE   ST_Distance(geomcol::geography,ST_SetSRID(ST_MakePoint(6.9333,46.8167),4326)::geography) < 30 * 1609.34
;

Aggregate  (cost=274167.33..274167.34 rows=1 width=0) (actual time=4940.531..4940.532 rows=1 loops=1)
  Output: count(*)
  ->  Seq Scan on bob.example1  (cost=0.00..273334.00 rows=333333 width=0) (actual time=592.766..4940.509 rows=11 loops=1)
        Output: idcol, geomcol
        Filter: (_st_distance((example1.geomcol)::geography, '0101000020E61000005D6DC5FEB2BB1B40545227A089684740'::geography, 0::double precision, true) < 48280.2::double precision)
        Rows Removed by Filter: 999989
Planning time: 2.137 ms
Execution time: 4940.568 ms

अब, यदि हम उपयोग करते हैं ST_DWithin, तो हमें अभी भी एक पूर्ण टेबल स्कैन मिलता है (यद्यपि यह अधिक तेज़ है):

EXPLAIN ANALYZE VERBOSE
SELECT  count(*)
FROM    example1
WHERE   ST_DWithin(geomcol::geography,ST_SetSRID(ST_MakePoint(6.9333,46.8167),4326)::geography,30 * 1609.34)
;

Aggregate  (cost=405867.33..405867.34 rows=1 width=0) (actual time=908.716..908.716 rows=1 loops=1)
  Output: count(*)
  ->  Seq Scan on bob.example1  (cost=0.00..405834.00 rows=13333 width=0) (actual time=38.449..908.700 rows=7 loops=1)
        Output: idcol, geomcol
        Filter: (((example1.geomcol)::geography && '0101000020E61000005D6DC5FEB2BB1B40545227A089684740'::geography) AND ('0101000020E61000005D6DC5FEB2BB1B40545227A089684740'::geography && _st_expand((example1.geomcol)::geography, 48280.2::double precision) (...)
        Rows Removed by Filter: 999993
Planning time: 2.017 ms
Execution time: 908.763 ms

और यह आखिरी टुकड़ा है - कवरिंग इंडेक्स (कास्ट भूगोल) का निर्माण:

CREATE INDEX example1_gpx ON example1 USING GIST (geography(geomcol));
-- (Takes an extra 13 sec)

EXPLAIN ANALYZE VERBOSE
SELECT  count(*)
FROM    example1
WHERE   ST_DWithin(geomcol::geography,ST_SetSRID(ST_MakePoint(6.9333,46.8167),4326)::geography,30 * 1609.34)
;

Aggregate  (cost=96538.95..96538.96 rows=1 width=0) (actual time=0.775..0.775 rows=1 loops=1)
  Output: count(*)
  ->  Bitmap Heap Scan on bob.example1  (cost=8671.62..96505.62 rows=13333 width=0) (actual time=0.586..0.769 rows=19 loops=1)
        Output: idcol, geomcol
        Recheck Cond: ((example1.geomcol)::geography && '0101000020E61000005D6DC5FEB2BB1B40545227A089684740'::geography)
        Filter: (('0101000020E61000005D6DC5FEB2BB1B40545227A089684740'::geography && _st_expand((example1.geomcol)::geography, 48280.2::double precision)) AND _st_dwithin((example1.geomcol)::geography, '0101000020E61000005D6DC5FEB2BB1B40545227A089684740':: (...)
        Rows Removed by Filter: 14
        Heap Blocks: exact=33
        ->  Bitmap Index Scan on example1_gpx  (cost=0.00..8668.29 rows=200000 width=0) (actual time=0.384..0.384 rows=33 loops=1)
              Index Cond: ((example1.geomcol)::geography && '0101000020E61000005D6DC5FEB2BB1B40545227A089684740'::geography)
Planning time: 2.572 ms
Execution time: 0.820 ms

अंत में, आशावादी स्थानिक सूचकांक का उपयोग कर रहा है, और यह दिखाता है, लेकिन दोस्तों के बीच परिमाण के तीन आदेश क्या हैं?

कुछ चेतावनी:

  • मैं एक डेटाबेस nerd हूं, इसलिए मेरे होम पीसी को 16 जीबी रैम, छह 3.3 जीएचजेड कोर, और डेटाबेस डिफ़ॉल्ट टेबलस्पेस के लिए 256 जीबी एसएसडी मिला है; आपकी माइलेज भिन्न हो सकती है

  • मैंने कैश के "हॉट" पेज के संबंध में प्लेइंग फील्ड को समतल करने के लिए प्रत्येक क्वेरी से पहले सृजन एसक्यूएल को फिर से चलाया, लेकिन यह थोड़ा अलग परिणाम दे सकता था क्योंकि एक ही यादृच्छिक बीज का उपयोग अलग-अलग रनों के लिए नहीं किया गया था।

और एक नोट:

  • मैंने समान क्षेत्र-वितरण के लिए चाप-कोसाइन का उपयोग करने के लिए मूल {-90, + 90} अक्षांश सीमा को छोटा कर दिया (ध्रुवों की ओर कम पक्षपाती)

1
यह स्टैकएक्सचेंज समुदाय में मुझे मिले सबसे अच्छे उत्तरों में से एक है। मैंने अभी भी यह कोशिश नहीं की, लेकिन आपने एक पूर्ण उदाहरण प्रदान किया जिसे मैं पूरी तरह से समझ सकता हूं। बहुत बहुत शुक्रिया @Vince।
anderpena

1
क्या भूगोल के रूप में भूगोल को संग्रहीत करने का कोई कारण नहीं है? ST_Distance और ST_DWithin दोनों ही भूगोल से अपेक्षा करते हैं। और अगर हमने ऐसा किया, तो हमें भूगोल में अतिरिक्त सूचकांक कास्टिंग ज्यामिति की आवश्यकता नहीं होगी।
andrpena

यह एक अलग सवाल है, और अगर पूछा जाए, तो इसे राय-आधारित के रूप में बंद किया जा सकता है।
विंस

1
Google में इस परिणाम पर आया और आपके उत्तर के लिए @Vince को धन्यवाद देता है। एक जियोग्रॉपी को एक जियोम पॉइंट को जबरदस्ती कास्टिंग करने का सबसे छोटा अंतर मेरी क्वेरी का समय औसतन 43 सेकंड से 10msec के बजाय लिया गया है ..
एंग्री 84

महान पोस्ट, लेकिन मुझे लगता है कि `(एसोस (1.0 - 2 * यादृच्छिक) () * 180.0) / पीआई ())` सही नहीं है। सीमा -90 से 90 तक नहीं है
hxd1011
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.