Tôi có một bảng chứa khoảng 55 triệu điểm dữ liệu (điểm là hình học có SRID 4326) và đối với truy vấn của tôi, tôi cần tham gia bảng này vào bảng khu vực (hiện có ~ 1800 khu vực) chứa nhiều loại khác nhau từ đa giác lớn ( 2000 km vuông) đến khá nhỏ (nhỏ khoảng 100 km vuông).
Truy vấn ban đầu được người dùng chọn thu hẹp 55 triệu điểm ban đầu xuống còn khoảng ~ 300.000 điểm tùy thuộc vào phạm vi ngày, v.v. họ chọn. Sau đó, phép nối được thực hiện và phụ thuộc vào khu vực mà họ đã chọn để sử dụng khi truy vấn hoàn tất, điều này thường thu hẹp nó xuống còn ~ 150.000.
Vấn đề tôi gặp phải là đôi khi truy vấn chỉ dừng lại và thay vì mất ~ 25 giây như mong đợi, có thể mất tới ~ 18 phút. Tại thời điểm này thường phải thực hiện PHÂN TÍCH VACUUM và sau đó chạy một vài truy vấn trước khi nó bắt đầu hoạt động trở lại. Không có dữ liệu nào được thêm, cập nhật hoặc xóa khỏi bảng dữ liệu hoặc khu vực tại thời điểm này.
Tôi đã chơi xung quanh với tất cả mọi thứ tôi có thể nghĩ và điều này dường như vẫn tiếp tục xảy ra mà không có sự bất ổn quá. Cả cột data.point và cột area.polygon đều có GIST INDEXES trên chúng.
Tôi thấy việc xóa INDEX khỏi cột data.point dường như làm mọi thứ ổn định hơn một chút nhưng chậm hơn bình thường ~ 35 giây. Tuy nhiên, loại bỏ INDEX dường như là một lựa chọn rất tồi vì nó có nên giúp không cản trở?
Tôi đang sử dụng PostgreSQL 9.1.4 với PostGIS 1.5
Đây là truy vấn tôi đang chạy
select * FROM data, area WHERE st_intersects (data.point, area.polygon) AND
(readingdatetime BETWEEN '1948-01-01' AND '2012-11-19') AND datasetid IN(3) AND
"polysetID" = 1 AND area.id IN(28,29,30,31,32,33,25,26,27,18,19,20,21,12,13,14,15,16,17,34,35,1,2,3,4,5,6,22,23,24,7,8,9,10,11)
GIẢI THÍCH
Nested Loop (cost=312.28..336.59 rows=5 width=2246) (actual time=1445.973..11557.824 rows=12723 loops=1)
Join Filter: _st_intersects(data.point, area.polygon)
-> Index Scan using "area_polysetID_index" on area (cost=0.00..20.04 rows=1 width=1949) (actual time=0.017..0.229 rows=35 loops=1)
Index Cond: ("polysetID" = 1)
Filter: (id = ANY ('{28,29,30,31,32,33,25,26,27,18,19,20,21,12,13,14,15,16,17,34,35,1,2,3,4,5,6,22,23,24,7,8,9,10,11}'::integer[]))
-> Bitmap Heap Scan on data (cost=312.28..316.29 rows=1 width=297) (actual time=328.771..329.136 rows=641 loops=35)
Recheck Cond: ((point && area.polygon) AND (datasetid = 3))"
Filter: ((readingdatetime >= '1948-01-01 00:00:00'::timestamp without time zone) AND (readingdatetime <= '2012-11-19 00:00:00'::timestamp without time zone))
-> BitmapAnd (cost=312.28..312.28 rows=1 width=0) (actual time=328.472..328.472 rows=0 loops=35)
-> Bitmap Index Scan on data_point_index (cost=0.00..24.47 rows=276 width=0) (actual time=307.115..307.115 rows=1365770 loops=35)
Index Cond: (point && area.polygon)
-> Bitmap Index Scan on data_datasetid_index (cost=0.00..284.37 rows=12856 width=0) (actual time=1.522..1.522 rows=19486 loops=35)
Index Cond: (datasetid = 3)
Total runtime: 11560.879 ms
Bảng tạo của tôi
CREATE TABLE data
(
id bigserial NOT NULL,
datasetid integer NOT NULL,
readingdatetime timestamp without time zone NOT NULL,
value double precision NOT NULL,
description character varying(255),
point geometry,
CONSTRAINT "DATAPRIMARYKEY" PRIMARY KEY (id ),
CONSTRAINT enforce_dims_point CHECK (st_ndims(point) = 2),
CONSTRAINT enforce_geotype_point CHECK (geometrytype(point) = 'POINT'::text OR point IS NULL),
CONSTRAINT enforce_srid_point CHECK (st_srid(point) = 4326)
);
CREATE INDEX data_datasetid_index ON data USING btree (datasetid);
ALTER TABLE data CLUSTER ON data_datasetid_index;
CREATE INDEX "data_datasetid_readingDatetime_index" ON data USING btree (datasetid , readingdatetime );
CREATE INDEX data_point_index ON data USING gist (point);
CREATE INDEX "data_readingDatetime_index" ON data USING btree (readingdatetime );
CREATE TABLE area
(
id serial NOT NULL,
polygon geometry,
"polysetID" integer NOT NULL,
CONSTRAINT area_primary_key PRIMARY KEY (id )
)
CREATE INDEX area_polygon_index ON area USING gist (polygon);
CREATE INDEX "area_polysetID_index" ON area USING btree ("polysetID");
ALTER TABLE area CLUSTER ON "area_polysetID_index";
Hy vọng rằng tất cả làm cho một mức độ ý nghĩa nếu cần biết bất cứ điều gì khác xin vui lòng yêu cầu.
Tóm tắt ngắn thực sự là INDEXES dường như hoạt động một số lần nhưng không phải là những người khác.
Bất cứ ai có thể đề nghị bất cứ điều gì tôi có thể cố gắng tìm ra những gì đang xảy ra?
Cảm ơn trước.
BIÊN TẬP:
Một vi dụ khac
select * FROM data, area WHERE st_intersects ( data.point, area.polygon) AND
(readingdatetime BETWEEN '2009-01-01' AND '2012-01-19') AND datasetid IN(1,3) AND
"polysetID" = 1 AND area.id IN(28,29,30,31,32,33,25,26,27,18,19,20,21,12,13,14,15,16,17,34,35,1,2,3,4,5,6,22,23,24,7,8,9,10,11)
Chạy trên bản sao của bảng với chỉ số điểm
Nested Loop (cost=0.00..1153.60 rows=35 width=2246) (actual time=86835.883..803363.979 rows=767 loops=1)
Join Filter: _st_intersects(data.point, area.polygon)
-> Index Scan using "area_polysetID_index" on area (cost=0.00..20.04 rows=1 width=1949) (actual time=0.021..16.287 rows=35 loops=1)
Index Cond: ("polysetID" = 1)
Filter: (id = ANY ('{28,29,30,31,32,33,25,26,27,18,19,20,21,12,13,14,15,16,17,34,35,1,2,3,4,5,6,22,23,24,7,8,9,10,11}'::integer[]))
-> Index Scan using data_point_index on data (cost=0.00..1133.30 rows=1 width=297) (actual time=17202.126..22952.706 rows=33 loops=35)
Index Cond: (point && area.polygon)
Filter: ((readingdatetime >= '2009-01-01 00:00:00'::timestamp without time zone) AND (readingdatetime <= '2012-01-19 00:00:00'::timestamp without time zone) AND (datasetid = ANY ('{1,3}'::integer[])))
Total runtime: 803364.120 ms
Chạy trên bản sao của bảng không có chỉ số điểm
Nested Loop (cost=2576.91..284972.54 rows=34 width=2246) (actual time=181.478..235.608 rows=767 loops=1)
Join Filter: ((data_new2.point && area.polygon) AND _st_intersects(data_new2.point, area.polygon))
-> Index Scan using "area_polysetID_index" on area (cost=0.00..20.04 rows=1 width=1949) (actual time=0.149..0.196 rows=35 loops=1)
Index Cond: ("polysetID" = 1)
Filter: (id = ANY ('{28,29,30,31,32,33,25,26,27,18,19,20,21,12,13,14,15,16,17,34,35,1,2,3,4,5,6,22,23,24,7,8,9,10,11}'::integer[]))
-> Bitmap Heap Scan on data_new2 (cost=2576.91..261072.36 rows=90972 width=297) (actual time=4.808..5.599 rows=2247 loops=35)
Recheck Cond: ((datasetid = ANY ('{1,3}'::integer[])) AND (readingdatetime >= '2009-01-01 00:00:00'::timestamp without time zone) AND (readingdatetime <= '2012-01-19 00:00:00'::timestamp without time zone))
-> Bitmap Index Scan on "data_new2_datasetid_readingDatetime_index" (cost=0.00..2554.16 rows=90972 width=0) (actual time=4.605..4.605 rows=2247 loops=35)
Index Cond: ((datasetid = ANY ('{1,3}'::integer[])) AND (readingdatetime >= '2009-01-01 00:00:00'::timestamp without time zone) AND (readingdatetime <= '2012-01-19 00:00:00'::timestamp without time zone))
Total runtime: 235.723 ms
Như bạn có thể thấy truy vấn chậm hơn đáng kể khi chỉ số điểm đang được sử dụng.
EDIT 2 (Truy vấn được đề xuất của Pauls):
WITH polys AS (
SELECT * FROM area
WHERE "polysetID" = 1 AND area.id IN(28,29,30,31,32,33,25,26,27,18,19,20,21,12,13,14,15,16,17,34,35,1,2,3,4,5,6,22,23,24,7,8,9,10,11)
)
SELECT *
FROM polys JOIN data ON ST_Intersects(data.point, polys.polygon)
WHERE datasetid IN(1,3)
AND (readingdatetime BETWEEN '2009-01-01' AND '2012-01-19');
GIẢI THÍCH
Nested Loop (cost=20.04..1155.43 rows=1 width=899) (actual time=16691.374..279065.402 rows=767 loops=1)
Join Filter: _st_intersects(data.point, polys.polygon)
CTE polys
-> Index Scan using "area_polysetID_index" on area (cost=0.00..20.04 rows=1 width=1949) (actual time=0.016..0.182 rows=35 loops=1)
Index Cond: ("polysetID" = 1)
Filter: (id = ANY ('{28,29,30,31,32,33,25,26,27,18,19,20,21,12,13,14,15,16,17,34,35,1,2,3,4,5,6,22,23,24,7,8,9,10,11}'::integer[]))
-> CTE Scan on polys (cost=0.00..0.02 rows=1 width=602) (actual time=0.020..0.358 rows=35 loops=1)
-> Index Scan using data_point_index on data (cost=0.00..1135.11 rows=1 width=297) (actual time=6369.327..7973.201 rows=33 loops=35)
Index Cond: (point && polys.polygon)
Filter: ((datasetid = ANY ('{1,3}'::integer[])) AND (readingdatetime >= '2009-01-01 00:00:00'::timestamp without time zone) AND (readingdatetime <= '2012-01-19 00:00:00'::timestamp without time zone))
Total runtime: 279065.540 ms