私は現在Postgres/PostGIS(1つの単一インスタンス)を使用していくつかのgeoクエリを実行し、特定の形状内にあるポイントと相対列からの追加データをキャッチしています。
ただし、インデックス(およびデータベースのスケールアップ)を使用しても、一部のクエリは遅すぎます。
Postgresの上でスムーズに動作するBrytLytのようなGPUデータベースを使用してみましたが、問題を解決しましたが、残念ながら非常に高すぎます(1時間あたりのAWSのコスト)。
レコードの合計量は〜1億回で、現時点でのクエリはそれぞれ6/7秒かかります(〜0.1秒程度必要です)。
問題に適したデータベースを提案できますか? 「手動の」シャーディングと事前計算値を回避しようとしています。
たとえば、特定のエリアに1つのベッドルームがある家の平均価格です。
これは現在のテーブルスキーマです。
Column | Type | Collation | Nullable | Default
-----------------------+------------------+-----------+----------+---------
uprn | bigint | | |
is_address_accurate | boolean | | |
postcode | text | | |
listing_type | text | | |
asking_price | double precision | | |
bedrooms | integer | | |
property_type | bpchar | | |
description | text | | |
total_floor_area_sqft | double precision | | |
date_appeared | date | | |
date_removed | date | | |
sold_price | double precision | | |
date_sold | date | | |
keywords | text | | |
asking_price_sqft | double precision | | |
sold_price_sqft | double precision | | |
days_on_market | integer | | |
images | text[] | | |
latitude | double precision | | |
longitude | double precision | | |
geom | geometry | | |
sector_ind | text | | |
district_ind | text | | |
area_ind | text | | |
total_floor_area | double precision | | |
transaction_type | text | | |
old_new | character(1) | | |
duration | character(1) | | |
floor_level | text | | |
floor_height | double precision | | |
current_energy_rating | text | | |
flat_top_storey | text | | |
flat_storey_count | smallint | | |
lodgement_date | date | | |
discount | double precision | | |
import_date | date | | |
building_number | smallint | | |
sub_building_name | text | | |
building_name | text | | |
thoroughfare | text | | |
post_town | text | | |
Indexes:
"sales_core_area_ind_idx" btree (area_ind)
"sales_core_area_ind_property_type_bedrooms_idx" btree (area_ind, property_type, bedrooms)
"sales_core_geom_idx" Gist (geom)
私が実行しているクエリの例:
explain analyze
select avg(sold_price)
from sales_core sc
where ST_Intersects(sc.geom, (select ST_Transform(ST_SetSRID(geometry, 4326), 2163)
from postcodes
where name = 'SW')
)
and bedrooms = 1
and property_type = 'F';
これは explain analyze
:
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=1656833.89..1656833.90 rows=1 width=8) (actual time=141286.194..141286.194 rows=1 loops=1)
InitPlan 1 (returns $0)
-> Seq Scan on postcodes (cost=0.00..3350.97 rows=1 width=2384) (actual time=14.079..19.155 rows=1 loops=1)
Filter: ((name)::text = 'SW'::text)
Rows Removed by Filter: 11836
-> Bitmap Heap Scan on sales_core sc (cost=834695.55..1653222.45 rows=104190 width=8) (actual time=141286.187..141286.187 rows=0 loops=1)
Recheck Cond: ((property_type = 'F'::bpchar) AND (bedrooms = 1))
Rows Removed by Index Recheck: 4447029
Filter: st_intersects(geom, $0)
Rows Removed by Filter: 1338789
Heap Blocks: exact=35516 lossy=241191
-> Bitmap Index Scan on sales_core_area_ind_property_type_bedrooms_idx (cost=0.00..834669.50 rows=312570 width=0) (actual time=2062.949..2062.949 rows=1338789 loops=1)
Index Cond: ((property_type = 'F'::bpchar) AND (bedrooms = 1))
Planning time: 0.192 ms
Execution time: 141307.039 ms
(15 rows)
[〜#〜]更新[〜#〜]
@Evan Carrollの回答からの提案に従って、いくつかの変更を適用しました。このようにして、「地理」タイプの新しい列を作成しました。
update listings set location_2 = ST_Point(longitude, latitude)::geography
クラスターの2つのステップでインデックスを作成しました(フィルターに追加のパラメーターはありません):
CREATE INDEX ON listings USING Gist(location_2);
CLUSTER listings ON using listings_location_2_idx;
地理に基づく純粋なルックアップのみを試行しているため、すべての余分なパラメーターを削除しました。
select count(*) from listings l join postcodes pc on ST_Intersects (l.location_2, ST_SetSRID(pc.geometry, 4326)::geography) where pc.name = 'SW';
最終結果:カウント| 929245時間:1661312.474ミリ秒(27:41.312)
カウントは正しいようですが(約100万レコード)、非常に遅すぎて実行できません(27分以上)。
私が何か間違ったことをしているかどうかはわかりません(ドキュメント全体を調べましたが、何かを失ったかもしれません)。
何か案が?
指定されたクエリプランに基づいて、postcodes.name
のインデックスが必要です
CREATE INDEX ON postcodes (name);
また、述語または複合によって、sales_coreのGistインデックスを修正することもできます。
CREATE EXTENSION btree_Gist;
CREATE INDEX ON sales_core USING Gist(property_type, bedrooms, geom);
私もhighly Geometry 4326として保存せず、代わりにGeography 4326として保存することをお勧めします。ST_IntersectsもJOINとして書き換える必要があります。
explain analyze
select avg(sold_price)
from sales_core sc
JOIN postcodes AS pc
ON ST_Intersects( sc.geom, pc.geometry)
WHERE bedrooms = 1
AND property_type = 'F'
AND pc.name = 'SW';
主な結合条件がGistの場合、クラスタリングは大きな違いをもたらします。おそらくPostGISのコンサルタントが必要です。助けてくれる私たちがたくさんいます。しかし、Pgからより多くのパフォーマンスを得ることができない理由はわかりません。