我有一張郊區表,每個郊區都有一個geom值,表示它在地圖上的多邊形。還有另一個房子的桌子,每個房子在地圖上都有一個geom值。Postgis ST_Intersects查詢不使用現有的空間索引
這兩個geom列都使用gist進行索引,而郊區表的名稱列也有索引。郊區表有8k +個記錄,而房屋表有300k +個記錄。
現在我的任務是找到一個名爲'FOO'的郊區內的所有房屋。
QUERY#1:
SELECT * FROM houses WHERE ST_INTERSECTS((SELECT geom FROM "suburbs" WHERE "suburb_name" = 'FOO'), geom);
查詢計劃結果:
Seq Scan on houses (cost=8.29..86327.26 rows=102365 width=136)
Filter: st_intersects($0, geom)
InitPlan 1 (returns $0)
-> Index Scan using suburbs_suburb_name on suburbs (cost=0.28..8.29 rows=1 width=32)
Index Cond: ((suburb_name)::text = 'FOO'::text)
運行查詢了〜3.5秒,返回486條記錄。
QUERY#2:(帶_前綴ST_INTERSECTS功能明確的告訴它不使用索引)
SELECT * FROM houses WHERE _ST_INTERSECTS((SELECT geom FROM "suburbs" WHERE "suburb_name" = 'FOO'), geom);
查詢計劃結果:(完全相同的查詢#1)
Seq Scan on houses (cost=8.29..86327.26 rows=102365 width=136)
Filter: st_intersects($0, geom)
InitPlan 1 (returns $0)
-> Index Scan using suburbs_suburb_name on suburbs (cost=0.28..8.29 rows=1 width=32)
Index Cond: ((suburb_name)::text = 'FOO'::text)
運行查詢花費了〜1.7s,返回了486條記錄。
QUERY#3:(使用& &運營商ST_Intersects函數之前添加一個邊界框重疊檢查)
SELECT * FROM houses WHERE (geom && (SELECT geom FROM "suburbs" WHERE "suburb_name" = 'FOO')) AND ST_INTERSECTS((SELECT geom FROM "suburbs" WHERE "suburb_name" = 'FOO'), geom);
查詢計劃結果:
Bitmap Heap Scan on houses (cost=21.11..146.81 rows=10 width=136)
Recheck Cond: (geom && $0)
Filter: st_intersects($1, geom)
InitPlan 1 (returns $0)
-> Index Scan using suburbs_suburb_name on suburbs (cost=0.28..8.29 rows=1 width=32)
Index Cond: ((suburb_name)::text = 'FOO'::text)
InitPlan 2 (returns $1)
-> Index Scan using suburbs_suburb_name on suburbs suburbs_1 (cost=0.28..8.29 rows=1 width=32)
Index Cond: ((suburb_name)::text = 'FOO'::text)
-> Bitmap Index Scan on houses_geom_gist (cost=0.00..4.51 rows=31 width=0)
Index Cond: (geom && $0)
運行查詢了0.15 s,返回486條記錄。
顯然只有查詢#3正在從顯着提高性能的空間索引中獲益。然而,這個語法很醜陋,並且在某種程度上重複着它自己。我的問題是:
- 爲什麼postgis不夠智能在查詢#1中使用空間索引?
- 爲什麼查詢#2與查詢#1相比具有(更多)更好的性能,因爲它們都不使用索引?
- 任何建議使查詢#3漂亮嗎?還是有更好的方法來構建查詢來做同樣的事情?
麥克指出,使用從兩個表並同時利用字符串和空間索引。它花了0.14s,並給出相同的結果集。 我也給JOIN一個去這樣: 選擇房屋。*從房子 JOIN郊區ST_Intersects(房屋。geom,suburbs.geom) WHERE suburbs.suburb_name ='FOO'; 它具有與來自兩個表的SELECT查詢相同的性能。所以兩者都可以接受。 我相信關鍵是要刪除子查詢。 –