I don't understand why the following query is so slow (with Postgresql 9.6):
SELECT s.pkid AS pkid_site , s.geom AS geom_site , z.pkid AS pkidEmprise, z.geom AS geom_emprise, z.précision_contour
FROM traitements.sites_candidats AS s
JOIN traitements.zones_sites AS z
ON z.pkid_site = s.pkid
WHERE s.statut = 'selected'
AND z.statut = 'selected';
The structure of the tables is the following:
CREATE TABLE traitements.sites_candidats (
pkid serial PRIMARY KEY,
statut varchar(255) NOT NULL,
geom geometry(Point, 2154)
);
CREATE INDEX ON traitements.sites_candidats (statut);
CREATE TABLE traitements.zones_sites (
pkid serial PRIMARY KEY,
pkid_site integer NOT NULL,
geom geometry(MultiPolygon,2154),
statut varchar(100)
);
CREATE INDEX zones_sites_idx_pkid_site ON traitements.zones_sites (pkid_site);
CREATE INDEX zones_sites_idx_statut ON traitements.zones_sites (statut) ;
ALTER TABLE traitements.zones_sites
ADD CONSTRAINT zones_sites_references_sites_candidats FOREIGN KEY (pkid_site) REFERENCES traitements.sites_candidats(pkid) ON DELETE CASCADE;
(I deleted a couple of columns that are not involved in the query in order to improve readability).
The result of EXPLAIN ANALYZE
:
Hash Join (cost=17709.29..152088.29 rows=147368 width=887) (actual time=137.074..879.884 rows=210708 loops=1)
Hash Cond: (z.pkid_site = s.pkid)
-> Seq Scan on zones_sites z (cost=0.00..85198.14 rows=210717 width=855) (actual time=0.140..384.964 rows=210708 loops=1)
Filter: ((statut)::text = 'selected'::text)
Rows Removed by Filter: 23
-> Hash (cost=13433.16..13433.16 rows=210490 width=36) (actual time=136.772..136.772 rows=210708 loops=1)
Buckets: 65536 Batches: 8 Memory Usage: 2191kB
-> Seq Scan on sites_candidats s (cost=0.00..13433.16 rows=210490 width=36) (actual time=3.085..87.774 rows=210708 loops=1)
Filter: ((statut)::text = 'selected'::text)
Rows Removed by Filter: 90265
Planning time: 0.386 ms
Execution time: 888.436 ms
It's obviously the JOIN .. ON
that consumes time because it does a hash.
Table traitements.sites_candidats
has about 300k rows (210k of them with statut='selected'
) and traitements.zones_sites
about 210k rows (nearly 99% of have statut='selected'). The query takes more than 4 minutes.