From 5aac209e8f1fe3c64a62ae2c51dac46d5b05a585 Mon Sep 17 00:00:00 2001 From: Sandro Santilli <strk@keybit.net> Date: Tue, 31 May 2016 07:22:50 +0000 Subject: [PATCH] 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. git-svn-id: http://svn.osgeo.org/postgis/trunk@14924 b70326c6-7e19-0410-871a-916f4a2858ee --- topology/postgis_topology.c | 38 ++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/topology/postgis_topology.c b/topology/postgis_topology.c index f0fbcc8fc..13fd5f394 100644 --- a/topology/postgis_topology.c +++ b/topology/postgis_topology.c @@ -79,6 +79,7 @@ struct LWT_BE_TOPOLOGY_T { int srid; double precision; int hasZ; + Oid geometryOID; }; /* utility funx */ @@ -156,7 +157,8 @@ cb_loadTopologyByName(const LWT_BE_DATA* be, const char *name) 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 @@ cb_loadTopologyByName(const LWT_BE_DATA* be, const char *name) 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 @@ cb_getFaceContainingPoint( const LWT_BE_TOPOLOGY* topo, const LWPOINT* pt ) 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); - - spi_result = SPI_execute(sql->data, !topo->be_data->data_changed, 1); + 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); + + 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", -- 2.40.0