[postgis-tickets] r14924 - Improve query performance in cb_getFaceContainingPoint

Sandro strk at kbt.io
Tue May 31 00:22:50 PDT 2016


Author: strk
Date: 2016-05-31 00:22:50 -0700 (Tue, 31 May 2016)
New Revision: 14924

Modified:
   trunk/topology/postgis_topology.c
Log:
Improve query performance in cb_getFaceContainingPoint

Avoids 1 output and 2 parse calls for hexwkb.
Was found reducing runtime from 23 seconds to 16 seconds for
adding a single polygon with a large shell and 129 holes
to an empty topology.

Modified: trunk/topology/postgis_topology.c
===================================================================
--- trunk/topology/postgis_topology.c	2016-05-31 07:22:42 UTC (rev 14923)
+++ trunk/topology/postgis_topology.c	2016-05-31 07:22:50 UTC (rev 14924)
@@ -79,6 +79,7 @@
   int srid;
   double precision;
   int hasZ;
+  Oid geometryOID;
 };
 
 /* utility funx */
@@ -156,7 +157,8 @@
   MemoryContext oldcontext = CurrentMemoryContext;
 
   initStringInfo(sql);
-  appendStringInfo(sql, "SELECT id,srid,precision FROM topology.topology "
+  appendStringInfo(sql, "SELECT id,srid,precision,null::geometry"
+                        " FROM topology.topology "
                         "WHERE name = '%s'", name);
   spi_result = SPI_execute(sql->data, !be->data_changed, 0);
   MemoryContextSwitchTo( oldcontext ); /* switch back */
@@ -216,6 +218,9 @@
     topo->precision = DatumGetFloat8(dat);
   }
 
+  /* we're dynamically querying geometry type here */
+  topo->geometryOID = SPI_tuptable->tupdesc->attrs[3]->atttypid;
+
   POSTGIS_DEBUGF(1, "cb_loadTopologyByName: topo '%s' has "
                     "id %d, srid %d, precision %g",
              name, topo->id, topo->srid, topo->precision);
@@ -2418,20 +2423,31 @@
   Datum dat;
   LWT_ELEMID face_id;
   size_t hexewkb_size;
-  char *hexewkb;
+  SPIPlanPtr plan;
+  GSERIALIZED *pts;
+  Datum values[1];
+  Oid argtypes[1];
 
   initStringInfo(sql);
 
-  hexewkb = lwgeom_to_hexwkb(lwpoint_as_lwgeom(pt), WKB_EXTENDED, &hexewkb_size);
+  pts = geometry_serialize(lwpoint_as_lwgeom(pt));
+  if ( ! pts ) {
+    cberror(topo->be_data, "%s:%d: could not serialize query point",
+            __FILE__, __LINE__);
+    return -2;
+  }
   /* TODO: call GetFaceGeometry internally, avoiding the round-trip to sql */
-  appendStringInfo(sql, "SELECT face_id FROM \"%s\".face "
-                        "WHERE mbr && '%s'::geometry AND ST_Contains("
-     "topology.ST_GetFaceGeometry('%s', face_id), "
-     "'%s'::geometry) LIMIT 1",
-      topo->name, hexewkb, topo->name, hexewkb);
-  lwfree(hexewkb);
+  appendStringInfo(sql,
+                   "SELECT face_id FROM \"%s\".face "
+                   "WHERE mbr && $1 AND _ST_Contains("
+                   "topology.ST_GetFaceGeometry('%s', face_id), $1)"
+                   " LIMIT 1",
+                   topo->name, topo->name);
 
-  spi_result = SPI_execute(sql->data, !topo->be_data->data_changed, 1);
+  values[0] = PointerGetDatum(pts);
+  argtypes[0] = topo->geometryOID;
+  spi_result = SPI_execute_with_args(sql->data, 1, argtypes, values, NULL,
+                                     !topo->be_data->data_changed, 1);
   MemoryContextSwitchTo( oldcontext ); /* switch back */
   if ( spi_result != SPI_OK_SELECT ) {
 		cberror(topo->be_data, "unexpected return (%d) from query execution: %s",



More information about the postgis-tickets mailing list