มีสองปุ่มเพื่อรับประสิทธิภาพการสืบค้น Geodetic ที่ดีกับตารางขนาดใหญ่ที่มี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 ดังนั้นพีซีที่บ้านของฉันจึงมี RAM 16Gb หกแกน 3.3Ghz หกและ 256Gb SSD สำหรับพื้นที่เริ่มต้นของฐานข้อมูล ไมล์สะสมของคุณอาจแตกต่างกันไป
ฉันเรียกใช้การสร้าง SQL ใหม่อีกครั้งก่อนการสืบค้นแต่ละครั้งเพื่อปรับระดับการเล่นที่เกี่ยวข้องกับหน้า "ร้อน" ในแคช แต่สิ่งนี้อาจให้ผลลัพธ์ที่แตกต่างกันเล็กน้อยเนื่องจากการสุ่มเมล็ดเดียวกันไม่ได้ใช้สำหรับการทำงานที่แตกต่างกัน
และหมายเหตุ:
- ฉัน tweaked ช่วงละติจูดดั้งเดิม {-90, + 90} เพื่อใช้ arc-cosine สำหรับการกระจายพื้นที่เท่ากัน (เอนเอียงน้อยลงไปที่ขั้ว)
ST_SetSRID()
กับการST_MakePoint
คัดลอกก่อนไปยังภูมิศาสตร์ในแบบสอบถาม