[postgis-tickets] r14926 - Improve query performance in cb_getEdgeByFace

Sandro strk at kbt.io
Tue May 31 03:07:55 PDT 2016


Author: strk
Date: 2016-05-31 03:07:55 -0700 (Tue, 31 May 2016)
New Revision: 14926

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

Avoids 1 output and 1 parse calls for hexwkb,
2 output and parse calls for integer arrays.
Was found reducing runtime from 16 seconds to 10 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:58:21 UTC (rev 14925)
+++ trunk/topology/postgis_topology.c	2016-05-31 10:07:55 UTC (rev 14926)
@@ -14,6 +14,8 @@
 #include "fmgr.h"
 #include "utils/elog.h"
 #include "utils/memutils.h" /* for TopMemoryContext */
+#include "utils/array.h" /* for ArrayType */
+#include "catalog/pg_type.h" /* for INT4OID */
 #include "lib/stringinfo.h"
 #include "access/xact.h" /* for RegisterXactCallback */
 #include "funcapi.h" /* for FuncCallContext */
@@ -114,15 +116,13 @@
   }
 }
 
-/* Return lwalloc'ed hexwkb representation for a GBOX */
-static char *
-_box2d_to_hexwkb(const GBOX *bbox, int srid)
+/* Return an lwalloc'ed geometrical representation of the box */
+static LWGEOM *
+_box2d_to_lwgeom(const GBOX *bbox, int srid)
 {
   POINTARRAY *pa = ptarray_construct(0, 0, 2);
   POINT4D p;
   LWLINE *line;
-  char *hex;
-  size_t sz;
 
   p.x = bbox->xmin;
   p.y = bbox->ymin;
@@ -131,8 +131,18 @@
   p.y = bbox->ymax;
   ptarray_set_point4d(pa, 1, &p);
   line = lwline_construct(srid, NULL, pa);
-  hex = lwgeom_to_hexwkb( lwline_as_lwgeom(line), WKT_EXTENDED, &sz);
-  lwline_free(line);
+  return lwline_as_lwgeom(line);
+}
+
+/* Return lwalloc'ed hexwkb representation for a GBOX */
+static char *
+_box2d_to_hexwkb(const GBOX *bbox, int srid)
+{
+  char *hex;
+  size_t sz;
+  LWGEOM *geom = _box2d_to_lwgeom(bbox, srid);
+  hex = lwgeom_to_hexwkb(geom, WKT_EXTENDED, &sz);
+  lwgeom_free(geom);
   assert(hex[sz-1] == '\0');
   return hex;
 }
@@ -872,34 +882,47 @@
   StringInfoData sqldata;
   StringInfo sql = &sqldata;
   int i;
-  char *hexbox;
+  ArrayType *array_ids;
+  Datum *datum_ids;
+  Datum values[2];
+  Oid argtypes[2];
+  int nargs = 1;
+  GSERIALIZED *gser = NULL;
 
+  datum_ids = palloc(sizeof(Datum)*(*numelems));
+  for (i=0; i<*numelems; ++i) datum_ids[i] = Int32GetDatum(ids[i]);
+  array_ids = construct_array(datum_ids, *numelems, INT4OID, 4, true, 's');
+
   initStringInfo(sql);
   appendStringInfoString(sql, "SELECT ");
   addEdgeFields(sql, fields, 0);
-  appendStringInfo(sql, " FROM \"%s\".edge_data", topo->name);
-  appendStringInfoString(sql, " WHERE ( left_face IN (");
-  // add all identifiers here
-  for (i=0; i<*numelems; ++i) {
-    appendStringInfo(sql, "%s%" LWTFMT_ELEMID, (i?",":""), ids[i]);
-  }
-  appendStringInfoString(sql, ") OR right_face IN (");
-  // add all identifiers here
-  for (i=0; i<*numelems; ++i) {
-    appendStringInfo(sql, "%s%" LWTFMT_ELEMID, (i?",":""), ids[i]);
-  }
-  appendStringInfoString(sql, ") )");
+  appendStringInfo(sql, " FROM \"%s\".edge_data"
+                        " WHERE ( left_face = ANY($1) "
+                        " OR right_face = ANY ($1) )",
+                   topo->name);
+
+  values[0] = PointerGetDatum(array_ids);
+  argtypes[0] = INT4ARRAYOID;
+
   if ( box )
   {
-    hexbox = _box2d_to_hexwkb(box, topo->srid);
-    appendStringInfo(sql, " AND geom && '%s'::geometry", hexbox);
-    lwfree(hexbox);
+    LWGEOM *g = _box2d_to_lwgeom(box, topo->srid);
+    gser = geometry_serialize(g);
+    lwgeom_free(g);
+    appendStringInfo(sql, " AND geom && $2");
+
+    values[1] = PointerGetDatum(gser);
+    argtypes[1] = topo->geometryOID;
+    ++nargs;
   }
 
   POSTGIS_DEBUGF(1, "cb_getEdgeByFace query: %s", sql->data);
   POSTGIS_DEBUGF(1, "data_changed is %d", topo->be_data->data_changed);
 
-  spi_result = SPI_execute(sql->data, !topo->be_data->data_changed, 0);
+  spi_result = SPI_execute_with_args(sql->data, nargs, argtypes, values, NULL,
+                                     !topo->be_data->data_changed, 0);
+  pfree(array_ids); /* not needed anymore */
+  if ( gser ) pfree(gser); /* not needed anymore */
   MemoryContextSwitchTo( oldcontext ); /* switch back */
   if ( spi_result != SPI_OK_SELECT ) {
 		cberror(topo->be_data, "unexpected return (%d) from query execution: %s", spi_result, sql->data);
@@ -2422,8 +2445,6 @@
   bool isnull;
   Datum dat;
   LWT_ELEMID face_id;
-  size_t hexewkb_size;
-  SPIPlanPtr plan;
   GSERIALIZED *pts;
   Datum values[1];
   Oid argtypes[1];



More information about the postgis-tickets mailing list