Hi
Thanks , this was fast code update .
Tested the code now but with geos 3.7 and the attached file and I still have
the same problem .
I assume there is something related to that I tested with geos 3.7.
I also had to test om another server with this cpu (Intel(R) Xeon(R) CPU
E3-1270 V2 @ 3.50GHz (fam: 06, model: 3a, stepping: 09)) where I was running
centos 7.
But I don't think this should make so much difference
Here is the test after the update on this server.
How I installed and compiled is further down the mail.
SELECT PostGIS_full_version();
postgis_full_version
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
POSTGIS="2.5.3dev r17378" [EXTENSION] PGSQL="110" GEOS="3.7.2dev-CAPI-1.11.2
995c7c4" SFCGAL="1.2.2" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.11.5,
released 2016/07/01" LIBXML="2.9.1" LIBJSON="0.11" TOPOLOGY RASTER
EXPLAIN ANALYZE
select (ST_dump(st_union(geo))).geom as geo
from sde_markslag.markslag_myrikilden_temp
where gid < 10000
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------
Result (cost=62634.10..62899.37 rows=1000 width=32) (actual
time=23445.338..23544.121 rows=9205 loops=1)
-> ProjectSet (cost=62634.10..62639.37 rows=1000 width=32) (actual
time=23445.333..23542.636 rows=9205 loops=1)
-> Aggregate (cost=62634.10..62634.11 rows=1 width=32) (actual
time=23442.220..23442.220 rows=1 loops=1)
-> Seq Scan on markslag_myrikilden_temp (cost=0.00..62609.51
rows=9835 width=1600) (actual time=0.015..178.305 rows=9999 loops=1)
Filter: (gid < 10000)
Rows Removed by Filter: 557242
Planning Time: 0.189 ms
Execution Time: 23544.779 ms
(8 rows)
Can I use 3.7 or do I have to compile the master branch together postgis 2.5 ?
I was not sure about what to merge from master into 3.7. So I just picked the
attached file from master and nothing else..
Then I removed postgis, gets and gdal installed by yum by using yum remove.
Then I Downloaded and compiled : The size was 521488 for
./src/operation/union/CascadedPolygonUnion.o
gdal branch 1.1 (Why do we use this old gdal ?)
geos branch 3.7 with a copy of CascadedPolygonUnion.cpp from master
postgis brach 2.5
./configure --with-geosconfig=/home/lop/postgres_code/geos/tools/geos-config
--with-pgconfig=/usr/pgsql-11/bin/pg_config
Then I got this error
./configure: line 13475: /home/lop/postgres_code/geos/tools/geos-config:
Permission denied
I added execute on that file then it compiled with ok and installed
PostGIS is now configured for x86_64-unknown-linux-gnu
-------------- Compiler Info -------------
C compiler: gcc -g -O2
SQL preprocessor: /usr/bin/cpp -traditional-cpp -w -P
-------------- Additional Info -------------
Interrupt Tests: DISABLED use: --with-interrupt-tests to enable
-------------- Dependencies --------------
GEOS config: /home/lop/postgres_code/geos/tools/geos-config
GEOS version: 3.7.2dev
GDAL config: /usr/local/bin/gdal-config
GDAL version: 1.11.5
SFCGAL config: /usr/bin/sfcgal-config
SFCGAL version: 1.2.2
PostgreSQL config: /usr/pgsql-11/bin/pg_config
PostgreSQL version: PostgreSQL 11.2
PROJ4 version: 48
Libxml2 config: /usr/bin/xml2-config
Libxml2 version: 2.9.1
JSON-C support: yes
protobuf-c support: no
PCRE support: no
Perl: /usr/bin/perl
--------------- Extensions ---------------
PostGIS Raster: enabled
PostGIS Topology: enabled
SFCGAL support: enabled
Address Standardizer support: disabled
-------- Documentation Generation --------
xsltproc: /usr/bin/xsltproc
xsl style sheets:
dblatex:
convert:
mathml2.dtd: http://www.w3.org/Math/DTD/mathml2/mathml2.dtd
To get work postgres I had to add this file
cat /etc/ld.so.conf.d/geos37-pgdg-libs.conf
/usr/local/lib/
And in /usr/local/lib I have these files
[root@vroomtest geos]# ls /usr/local/lib
gdalplugins libgdal.la libgdal.so.1 libgeos-3.7.2.so libgeos_c.a
libgeos_c.so libgeos_c.so.1.11.2 libgeos.so liblwgeom-2.5.so.0.0.0
liblwgeom.la pkgconfig
libgdal.a libgdal.so libgdal.so.1.18.5 libgeos.a libgeos_c.la
libgeos_c.so.1 libgeos.la liblwgeom-2.5.so.0 liblwgeom.a
liblwgeom.so
Then I started postgres and created a new database and adde the postgis
extension and added the testdata.
Thanks .
Lars
________________________________
From: postgis-users <[email protected]> on behalf of Martin
Davis <[email protected]>
Sent: Friday, April 12, 2019 11:36 PM
To: PostGIS Users Discussion
Subject: Re: [postgis-users] diffrent execution plan on Postgres 9.5 and
Postgres 11 for ST_union and performance problem Postgres 11
I've figured out a fix for the performance reqression and it's now in GEOS
master. My testing using the sample data provided above indicates it's at
least 10x faster, so essentially eliminating the performance regression in this
case (and it should provide that for most situations)
If anyone can test further to confirm it is indeed faster and most importantly
correct that would be great.
On Thu, Apr 11, 2019 at 1:03 PM Martin Davis
<[email protected]<mailto:[email protected]>> wrote:
Well, we have figured out what the problem is - it's a known regression in the
GEOS UnaryUnion code, reported in this ticket [1]
Unfortunately there's no fix for this yet, but we'll try and escalate this.
[1] https://trac.osgeo.org/geos/ticket/867
/**********************************************************************
*
* GEOS - Geometry Engine Open Source
* http://geos.osgeo.org
*
* Copyright (C) 2011 Sandro Santilli <[email protected]>
* Copyright (C) 2006 Refractions Research Inc.
*
* This is free software; you can redistribute and/or modify it under
* the terms of the GNU Lesser General Public Licence as published
* by the Free Software Foundation.
* See the COPYING file for more information.
*
**********************************************************************
*
* Last port: operation/union/CascadedPolygonUnion.java r487 (JTS-1.12+)
* Includes custom code to deal with https://trac.osgeo.org/geos/ticket/837
*
**********************************************************************/
#include <geos/operation/union/CascadedPolygonUnion.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/Polygon.h>
#include <geos/geom/MultiPolygon.h>
#include <geos/geom/util/GeometryCombiner.h>
#include <geos/geom/util/PolygonExtracter.h>
#include <geos/index/strtree/STRtree.h>
// std
#include <cassert>
#include <cstddef>
#include <memory>
#include <vector>
#include <sstream>
#include <geos/operation/valid/IsValidOp.h>
#include <geos/operation/IsSimpleOp.h>
#include <geos/algorithm/BoundaryNodeRule.h>
#include <geos/util/TopologyException.h>
#include <string>
#include <iomanip>
//#define GEOS_DEBUG_CASCADED_UNION 1
//#define GEOS_DEBUG_CASCADED_UNION_PRINT_INVALID 1
namespace {
inline bool
check_valid(const geos::geom::Geometry& g, const std::string& label, bool
doThrow = false, bool validOnly = false)
{
using namespace geos;
if(dynamic_cast<const geos::geom::Lineal*>(&g)) {
if(! validOnly) {
operation::IsSimpleOp sop(g,
algorithm::BoundaryNodeRule::getBoundaryEndPoint());
if(! sop.isSimple()) {
if(doThrow) {
throw geos::util::TopologyException(
label + " is not simple");
}
return false;
}
}
}
else {
operation::valid::IsValidOp ivo(&g);
if(! ivo.isValid()) {
using operation::valid::TopologyValidationError;
TopologyValidationError* err = ivo.getValidationError();
#ifdef GEOS_DEBUG_CASCADED_UNION
std::cerr << label << " is INVALID: "
<< err->toString()
<< " (" << std::setprecision(20)
<< err->getCoordinate() << ")"
<< std::endl
#ifdef GEOS_DEBUG_CASCADED_UNION_PRINT_INVALID
<< "<a>" << std::endl
<< g.toString() << std::endl
<< "</a>" << std::endl
#endif
;
#endif // GEOS_DEBUG_CASCADED_UNION
if(doThrow) {
throw geos::util::TopologyException(
label + " is invalid: " + err->toString(),
err->getCoordinate());
}
return false;
}
}
return true;
}
} // anonymous namespace
namespace geos {
namespace operation { // geos.operation
namespace geounion { // geos.operation.geounion
///////////////////////////////////////////////////////////////////////////////
void
GeometryListHolder::deleteItem(geom::Geometry* item)
{
delete item;
}
///////////////////////////////////////////////////////////////////////////////
geom::Geometry*
CascadedPolygonUnion::Union(std::vector<geom::Polygon*>* polys)
{
CascadedPolygonUnion op(polys);
return op.Union();
}
geom::Geometry*
CascadedPolygonUnion::Union(const geom::MultiPolygon* multipoly)
{
std::vector<geom::Polygon*> polys;
typedef geom::MultiPolygon::const_iterator iterator;
iterator end = multipoly->end();
for(iterator i = multipoly->begin(); i != end; ++i) {
polys.push_back(dynamic_cast<geom::Polygon*>(*i));
}
CascadedPolygonUnion op(&polys);
return op.Union();
}
geom::Geometry*
CascadedPolygonUnion::Union()
{
if(inputPolys->empty()) {
return nullptr;
}
geomFactory = inputPolys->front()->getFactory();
/**
* A spatial index to organize the collection
* into groups of close geometries.
* This makes unioning more efficient, since vertices are more likely
* to be eliminated on each round.
*/
index::strtree::STRtree index(STRTREE_NODE_CAPACITY);
typedef std::vector<geom::Polygon*>::iterator iterator_type;
iterator_type end = inputPolys->end();
for(iterator_type i = inputPolys->begin(); i != end; ++i) {
geom::Geometry* g = dynamic_cast<geom::Geometry*>(*i);
index.insert(g->getEnvelopeInternal(), g);
}
std::unique_ptr<index::strtree::ItemsList> itemTree(index.itemsTree());
return unionTree(itemTree.get());
}
geom::Geometry*
CascadedPolygonUnion::unionTree(
index::strtree::ItemsList* geomTree)
{
/**
* Recursively unions all subtrees in the list into single geometries.
* The result is a list of Geometry's only
*/
std::unique_ptr<GeometryListHolder> geoms(reduceToGeometries(geomTree));
return binaryUnion(geoms.get());
}
geom::Geometry*
CascadedPolygonUnion::binaryUnion(GeometryListHolder* geoms)
{
return binaryUnion(geoms, 0, geoms->size());
}
geom::Geometry*
CascadedPolygonUnion::binaryUnion(GeometryListHolder* geoms,
std::size_t start, std::size_t end)
{
if(end - start <= 1) {
return unionSafe(geoms->getGeometry(start), nullptr);
}
else if(end - start == 2) {
return unionSafe(geoms->getGeometry(start), geoms->getGeometry(start +
1));
}
else {
// recurse on both halves of the list
std::size_t mid = (end + start) / 2;
std::unique_ptr<geom::Geometry> g0(binaryUnion(geoms, start, mid));
std::unique_ptr<geom::Geometry> g1(binaryUnion(geoms, mid, end));
return unionSafe(g0.get(), g1.get());
}
}
GeometryListHolder*
CascadedPolygonUnion::reduceToGeometries(index::strtree::ItemsList* geomTree)
{
std::unique_ptr<GeometryListHolder> geoms(new GeometryListHolder());
typedef index::strtree::ItemsList::iterator iterator_type;
iterator_type end = geomTree->end();
for(iterator_type i = geomTree->begin(); i != end; ++i) {
if((*i).get_type() == index::strtree::ItemsListItem::item_is_list) {
std::unique_ptr<geom::Geometry>
geom(unionTree((*i).get_itemslist()));
geoms->push_back_owned(geom.get());
geom.release();
}
else if((*i).get_type() ==
index::strtree::ItemsListItem::item_is_geometry) {
geoms->push_back(reinterpret_cast<geom::Geometry*>((*i).get_geometry()));
}
else {
assert(!static_cast<bool>("should never be reached"));
}
}
return geoms.release();
}
geom::Geometry*
CascadedPolygonUnion::unionSafe(geom::Geometry* g0, geom::Geometry* g1)
{
if(g0 == nullptr && g1 == nullptr) {
return nullptr;
}
if(g0 == nullptr) {
return g1->clone();
}
if(g1 == nullptr) {
return g0->clone();
}
return unionOptimized(g0, g1);
}
geom::Geometry*
CascadedPolygonUnion::unionOptimized(geom::Geometry* g0, geom::Geometry* g1)
{
geom::Envelope const* g0Env = g0->getEnvelopeInternal();
geom::Envelope const* g1Env = g1->getEnvelopeInternal();
if(!g0Env->intersects(g1Env)) {
return geom::util::GeometryCombiner::combine(g0, g1);
}
if(g0->getNumGeometries() <= 1 && g1->getNumGeometries() <= 1) {
return unionActual(g0, g1);
}
geom::Envelope commonEnv;
g0Env->intersection(*g1Env, commonEnv);
return unionUsingEnvelopeIntersection(g0, g1, commonEnv);
}
/* private */
geom::Geometry*
CascadedPolygonUnion::unionUsingEnvelopeIntersection(geom::Geometry* g0,
geom::Geometry* g1, geom::Envelope const& common)
{
std::vector<geom::Geometry*> disjointPolys;
#if GEOS_DEBUG_CASCADED_UNION
check_valid(*g0, "unionUsingEnvelopeIntersection g0");
check_valid(*g1, "unionUsingEnvelopeIntersection g1");
#endif
std::unique_ptr<geom::Geometry> g0Int(extractByEnvelope(common, g0,
disjointPolys));
std::unique_ptr<geom::Geometry> g1Int(extractByEnvelope(common, g1,
disjointPolys));
#if GEOS_DEBUG_CASCADED_UNION
check_valid(*g0Int, "unionUsingEnvelopeIntersection g0Int");
check_valid(*g1Int, "unionUsingEnvelopeIntersection g1Int");
#endif
std::unique_ptr<geom::Geometry> u(unionActual(g0Int.get(), g1Int.get()));
#if GEOS_DEBUG_CASCADED_UNION
if(! check_valid(*u, "unionUsingEnvelopeIntersection unionActual return")) {
#if GEOS_DEBUG_CASCADED_UNION_PRINT_INVALID
std::cerr << " union between the following is invalid"
<< "<a>" << std::endl
<< *g0Int << std::endl
<< "</a>" << std::endl
<< "<b>" << std::endl
<< *g1Int << std::endl
<< "</b>" << std::endl
;
#endif
}
#endif
if(disjointPolys.empty()) {
return u.release();
}
#if GEOS_DEBUG_CASCADED_UNION
for(size_t i = 0; i < disjointPolys.size(); ++i) {
std::ostringstream os;
os << "dp" << i;
check_valid(*(disjointPolys[i]), os.str());
}
#endif
// TODO: find, in disjointPolys, those which now have their
// environment intersect the environment of the union "u"
// and collect them in another vector to be unioned
std::vector<geom::Geometry*> polysOn;
std::vector<geom::Geometry*> polysOff;
geom::Envelope const* uEnv = u->getEnvelopeInternal(); // TODO: check for
EMPTY ?
extractByEnvelope(*uEnv, disjointPolys, polysOn, polysOff);
#if GEOS_DEBUG_CASCADED_UNION
std::cerr << "unionUsingEnvelopeIntersection: " << polysOn.size() << "/" <<
disjointPolys.size() <<
" polys intersect union of final thing" << std::endl;
#endif
std::unique_ptr<geom::Geometry> ret;
if(polysOn.empty()) {
disjointPolys.push_back(u.get());
ret.reset(geom::util::GeometryCombiner::combine(disjointPolys));
}
else {
// TODO: could be further tweaked to only union with polysOn
// and combine with polysOff, but then it'll need again to
// recurse in the check for disjoint/intersecting
ret.reset(geom::util::GeometryCombiner::combine(disjointPolys));
ret.reset(unionActual(ret.get(), u.get()));
}
#if GEOS_DEBUG_CASCADED_UNION
check_valid(*ret, "unionUsingEnvelopeIntersection returned geom");
#endif
return ret.release();
}
/* private */
void
CascadedPolygonUnion::extractByEnvelope(geom::Envelope const& env,
std::vector<geom::Geometry*>&
sourceGeoms,
std::vector<geom::Geometry*>&
intersectingGeoms,
std::vector<geom::Geometry*>&
disjointGeoms)
{
for(std::vector<geom::Geometry*>::iterator i = sourceGeoms.begin(),
e = sourceGeoms.end(); i != e; ++i) {
geom::Geometry* elem = *i;
if(elem->getEnvelopeInternal()->intersects(env)) {
intersectingGeoms.push_back(elem);
}
else {
disjointGeoms.push_back(elem);
}
}
}
/* private */
void
CascadedPolygonUnion::extractByEnvelope(geom::Envelope const& env,
geom::Geometry* geom,
std::vector<geom::Geometry*>&
intersectingGeoms,
std::vector<geom::Geometry*>&
disjointGeoms)
{
for(std::size_t i = 0; i < geom->getNumGeometries(); i++) {
geom::Geometry* elem =
const_cast<geom::Geometry*>(geom->getGeometryN(i));
if(elem->getEnvelopeInternal()->intersects(env)) {
intersectingGeoms.push_back(elem);
}
else {
disjointGeoms.push_back(elem);
}
}
}
/* private */
geom::Geometry*
CascadedPolygonUnion::extractByEnvelope(geom::Envelope const& env,
geom::Geometry* geom,
std::vector<geom::Geometry*>& disjointGeoms)
{
std::vector<geom::Geometry*> intersectingGeoms;
extractByEnvelope(env, geom, intersectingGeoms, disjointGeoms);
return geomFactory->buildGeometry(intersectingGeoms);
}
geom::Geometry*
CascadedPolygonUnion::unionActual(geom::Geometry* g0, geom::Geometry* g1)
{
return
restrictToPolygons(std::unique_ptr<geom::Geometry>(g0->Union(g1))).release();
}
std::unique_ptr<geom::Geometry>
CascadedPolygonUnion::restrictToPolygons(std::unique_ptr<geom::Geometry> g)
{
using namespace geom;
using namespace std;
if(dynamic_cast<Polygonal*>(g.get())) {
return g;
}
Polygon::ConstVect polygons;
geom::util::PolygonExtracter::getPolygons(*g, polygons);
if(polygons.size() == 1) {
return std::unique_ptr<Geometry>(polygons[0]->clone());
}
typedef vector<Geometry*> GeomVect;
Polygon::ConstVect::size_type n = polygons.size();
GeomVect* newpolys = new GeomVect(n);
for(Polygon::ConstVect::size_type i = 0; i < n; ++i) {
(*newpolys)[i] = polygons[i]->clone();
}
return unique_ptr<Geometry>(
g->getFactory()->createMultiPolygon(newpolys)
);
}
} // namespace geos.operation.union
} // namespace geos.operation
} // namespace geos
_______________________________________________
postgis-users mailing list
[email protected]
https://lists.osgeo.org/mailman/listinfo/postgis-users