ST_DWinin était plus rapide dans mon test que ST_Intersects. C'est surprenant, d'autant plus que l'algorithme de géométrie préparée est censé intervenir dans de tels cas. Je pense qu'il y a une chance que ce soit beaucoup plus rapide que ce que j'ai montré ici.
J'ai fait quelques tests supplémentaires et deux choses ont presque doublé la vitesse. Premièrement, j'ai essayé sur un ordinateur plus récent, mais toujours un ordinateur portable assez ordinaire, peut-être à l'exception des disques SATA3 ssd.
Ensuite, la requête ci-dessous a pris 18 secondes au lieu de 62 secondes sur l'ancien ordinateur portable. Ensuite, j'ai découvert que j'avais totalement tort avant d'écrire que l'index de la table de points n'était pas nécessaire. Avec cet index en place, ST_Intersects s'est comporté comme prévu et les choses sont devenues très rapides. J'ai augmenté le nombre de points dans la table de points à 1 million de points et la requête:
CREATE TABLE points_ct AS
SELECT imported_ct.gid as ct_gid, t.gid as point_id
FROM imported_ct , t WHERE ST_Intersects(imported_ct.geom , t.geom);
fonctionne en 72 secondes. Comme il y a 1249 polygones, 1249000000 tests sont effectués en 72 secondes. Cela fait environ 17000000 tests par seconde. Ou tester près de 14 000 points contre tous les polygones par seconde.
À partir de ce test, les 400000000 points à tester devraient prendre environ 8 heures sans aucun problème pour répartir la charge sur plusieurs cœurs. PostGIS ne cesse jamais de m'impressionner :-)
Tout d'abord, pour visualiser le résultat, vous pouvez ajouter la géométrie de point à la table résultante, l'ouvrir par exemple dans QGIS et la styliser avec des valeurs uniques sur le champ imports_ct.
Deuxièmement, vous pouvez également obtenir les points situés en dehors de tout polygone en utilisant une jointure à droite (ou à gauche) comme ceci:
CREATE TABLE points_ct AS
SELECT imported_ct.gid as ct_gid, t.gid as point_id
FROM imported_ct right join t ON ST_Intersects(imported_ct.the_geom , t.geom);
J'ai fait des tests pour vérifier si cela semble possible PostGIS.
D'abord quelque chose que je ne comprends pas. Vous avez deux points par ligne. Les deux points sont-ils toujours dans le même polygone? Ensuite, il suffit de faire les calculs sur l’un des points. S'ils peuvent être dans deux polygones différents, vous aurez besoin d'un moyen de connecter une ligne de point à deux polygones.
D'après les tests, cela semble faisable, mais vous aurez peut-être besoin d'une solution créative pour répartir la charge sur plusieurs cpu-core.
J'ai testé sur un ordinateur portable de 4 ans avec processeur double cœur centrino (environ 2,2 GHz, je pense), 2 Go de RAM. Si vous avez 48 Go de RAM, je suppose que vous avez aussi beaucoup plus de puissance CPU.
Ce que j'ai fait était de créer une table de points aléatoires avec 100 000 points comme ceci:
CREATE TABLE t AS
WITH r AS
(SELECT ST_Extent(the_geom)::geometry ext FROM imported_ct)
SELECT ST_Point(x,y) AS geom FROM
(SELECT GENERATE_SERIES(1,100000)) s,
(SELECT ST_Xmin(ext)+(random()*(ST_Xmax(ext)-ST_Xmin(ext))) x, ST_Ymin(ext)+(random()*(ST_Ymax(ext)-ST_Ymin(ext))) y FROM r
) f;
Puis ajouter un gid comme:
ALTER TABLE t ADD COLUMN GID SERIAL;
Puis en cours d'exécution:
CREATE TABLE points_ct AS
SELECT imported_ct.gid as ct_gid, t.gid as point_id FROM imported_ct , t WHERE ST_Dwithin(imported_ct.the_geom , t.geom,0);
prend environ 62 secondes (comparez votre résultat à ArcGIS avec le même nombre de points). Le résultat est un tableau reliant les points de mon tableau t au gid du tableau avec le secteur de recensement.
Avec cette vitesse, vous obtiendrez 200 points en 34 heures environ. Donc, s'il suffit de vérifier l'un des points, mon ancien ordinateur portable peut le faire avec un seul noyau.
Mais si vous devez vérifier les deux points, cela pourrait être plus difficile.
Ensuite, vous pouvez répartir manuellement la charge sur plusieurs cœurs en démarrant plusieurs sessions sur la base de données et en exécutant différentes requêtes.
Dans mon exemple avec 50000 points et deux cœurs de processeur, j'ai essayé:
CREATE TABLE t1 as
SELECT imported_ct.gid as ct_gid, t.gid as point_id FROM imported_ct , t WHERE t.gid >50000 and ST_Dwithin(imported_ct.the_geom , t.geom,0);
sur une session de base de données en même temps que l'exécution:
CREATE TABLE t2 as
SELECT imported_ct.gid as ct_gid, t.gid as point_id FROM imported_ct , t WHERE t.gid <=50000 and ST_Dwithin(imported_ct.the_geom , t.geom,0);
sur une autre db-session.
Cela a pris environ 36 secondes, il est donc un peu plus lent que le premier exemple, probablement en fonction de l’écriture du disque en même temps. Mais comme les deux noyaux fonctionnent simultanément, cela ne m'a pas pris plus de 36 secondes de mon temps.
Pour joindre les tables t1 et t2 a essayé:
CREATE TABLE t3 AS
SELECT * FROM t1
UNION ALL
SELECT * FROM t2;
en utilisant environ une demi-seconde.
Ainsi, avec du matériel plus récent et une répartition de la charge sur de nombreux cœurs, cela devrait absolument être possible, même si le monde réel sera plus lent que le scénario de test.
Il convient de noter que l'exemple provient de Linux (Ubuntu). Utiliser Windows sera une autre histoire. Mais toutes les autres applications quotidiennes sont en cours d’exécution, de sorte que l’ordinateur portable est assez chargé d’avant. Cela pourrait donc très bien simuler le cas Windows, sans rien ouvrir d'autre que pgadmin.