geometry
WGS 1984 भौगोलिक डेटा (SRID 4326) का उपयोग करते हुए स्तंभों के साथ बड़े तालिकाओं के साथ अच्छा जियोडेटिक क्वेरी प्रदर्शन प्राप्त करने के लिए दो कुंजी हैं :
- उपयोग
ST_DWithin
फ़ंक्शन का , जो एक उपलब्ध स्थानिक इंडेक्स का उपयोग करके खोज करता है, और एक कार्टेशियन दूरी के साथ भूगोल सुविधाओं को ढूंढेगा
- भूगोल कास्ट पर एक अतिरिक्त इंडेक्स बनाएं, ताकि
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} अक्षांश सीमा को छोटा कर दिया (ध्रुवों की ओर कम पक्षपाती)
ST_SetSRID()
करने के लिएST_MakePoint
क्वेरी में भूगोल के लिए कास्टिंग से पहले।