@@ -73,8 +73,8 @@ static void load_id_list(pg_conn_t const &db_connection,
7373 std::string const &table,
7474 osmium::index::IdSetSmall<osmid_t > *ids)
7575{
76- auto const res =
77- db_connection. exec ( fmt::format (" SELECT id FROM {} ORDER BY id" , table));
76+ auto const res = db_connection. exec (
77+ fmt::format (" SELECT DISTINCT id FROM {} ORDER BY id" , table));
7878 for (int n = 0 ; n < res.num_tuples (); ++n) {
7979 ids->set (osmium::string_to_object_id (res.get_value (n, 0 )));
8080 }
@@ -822,48 +822,69 @@ void middle_pgsql_t::get_node_parents(
822822
823823 send_id_list (m_db_connection, " osm2pgsql_changed_nodes" , changed_nodes);
824824
825- m_db_connection.exec (" ANALYZE osm2pgsql_changed_nodes" );
825+ std::vector<std::string> queries;
826+
827+ queries.emplace_back (" ANALYZE osm2pgsql_changed_nodes" );
826828
827829 bool const has_bucket_index =
828830 check_bucket_index (&m_db_connection, m_options->prefix );
829831
830832 if (has_bucket_index) {
831- m_db_connection.exec (build_sql (*m_options, R"(
832- WITH changed_buckets AS (
833- SELECT array_agg(id) AS node_ids, id >> {way_node_index_id_shift} AS bucket
834- FROM osm2pgsql_changed_nodes GROUP BY id >> {way_node_index_id_shift}
835- )
836- INSERT INTO osm2pgsql_changed_ways
837- SELECT DISTINCT w.id
838- FROM {schema}"{prefix}_ways" w, changed_buckets b
839- WHERE w.nodes && b.node_ids
840- AND {schema}"{prefix}_index_bucket"(w.nodes)
841- && ARRAY[b.bucket];
842- )" ));
833+ // The query to get the parent ways of changed nodes is "hidden"
834+ // inside a PL/pgSQL function so that the query planner only sees
835+ // a single node id that is being queried for. If we ask for all
836+ // nodes at the same time the query planner sometimes thinks it is
837+ // better to do a full table scan which totally destroys performance.
838+ // This is due to the PostgreSQL statistics on ARRAYs being way off.
839+ queries.emplace_back (R"(
840+ CREATE OR REPLACE FUNCTION osm2pgsql_find_changed_ways() RETURNS void AS $$
841+ DECLARE
842+ changed_buckets RECORD;
843+ BEGIN
844+ FOR changed_buckets IN
845+ SELECT array_agg(id) AS node_ids, id >> {way_node_index_id_shift} AS bucket
846+ FROM osm2pgsql_changed_nodes GROUP BY id >> {way_node_index_id_shift}
847+ LOOP
848+ INSERT INTO osm2pgsql_changed_ways
849+ SELECT DISTINCT w.id
850+ FROM {schema}"{prefix}_ways" w
851+ WHERE w.nodes && changed_buckets.node_ids
852+ AND {schema}"{prefix}_index_bucket"(w.nodes)
853+ && ARRAY[changed_buckets.bucket];
854+ END LOOP;
855+ END;
856+ $$ LANGUAGE plpgsql
857+ )" );
858+ queries.emplace_back (" SELECT osm2pgsql_find_changed_ways()" );
859+ queries.emplace_back (" DROP FUNCTION osm2pgsql_find_changed_ways()" );
843860 } else {
844- m_db_connection. exec ( build_sql (*m_options, R"(
861+ queries. emplace_back ( R"(
845862INSERT INTO osm2pgsql_changed_ways
846- SELECT DISTINCT w.id
863+ SELECT w.id
847864 FROM {schema}"{prefix}_ways" w, osm2pgsql_changed_nodes n
848865 WHERE w.nodes && ARRAY[n.id]
849- )" )) ;
866+ )" );
850867 }
851868
852869 if (m_options->middle_database_format == 1 ) {
853- m_db_connection. exec ( build_sql (*m_options, R"(
870+ queries. emplace_back ( R"(
854871INSERT INTO osm2pgsql_changed_relations
855- SELECT DISTINCT r.id
872+ SELECT r.id
856873 FROM {schema}"{prefix}_rels" r, osm2pgsql_changed_nodes n
857874 WHERE r.parts && ARRAY[n.id]
858875 AND r.parts[1:way_off] && ARRAY[n.id]
859- )" )) ;
876+ )" );
860877 } else {
861- m_db_connection. exec ( build_sql (*m_options, R"(
878+ queries. emplace_back ( R"(
862879INSERT INTO osm2pgsql_changed_relations
863- SELECT DISTINCT r.id
880+ SELECT r.id
864881 FROM {schema}"{prefix}_rels" r, osm2pgsql_changed_nodes c
865882 WHERE {schema}"{prefix}_member_ids"(r.members, 'N'::char) && ARRAY[c.id];
866- )" ));
883+ )" );
884+ }
885+
886+ for (auto const &query : queries) {
887+ m_db_connection.exec (build_sql (*m_options, query));
867888 }
868889
869890 load_id_list (m_db_connection, " osm2pgsql_changed_ways" , parent_ways);
0 commit comments