From: Sarah Hoffmann Date: Fri, 9 Oct 2020 15:20:22 +0000 (+0200) Subject: add script for detailed explaing of indexing trigger X-Git-Tag: v3.6.0~57^2 X-Git-Url: https://git.openstreetmap.org./nominatim.git/commitdiff_plain/ec5743bcc04aea281e4e51aedf80d270530fdf7d?ds=sidebyside;hp=-c add script for detailed explaing of indexing trigger --- ec5743bcc04aea281e4e51aedf80d270530fdf7d diff --git a/utils/analyse_indexing.py b/utils/analyse_indexing.py new file mode 100755 index 00000000..d461f891 --- /dev/null +++ b/utils/analyse_indexing.py @@ -0,0 +1,119 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: GPL-2.0-only +# +# This file is part of Nominatim. +# Copyright (C) 2020 Sarah Hoffmann + +""" +Script for analysing the indexing process. + +The script enables detailed logging for nested statements and then +runs the indexing process for teh given object. Detailed 'EXPLAIN ANALYSE' +information is printed for each executed query in the trigger. The +transaction is then rolled back, so that no actual changes to the database +happen. It also disables logging into the system log, so that the +log files are not cluttered. +""" + +from argparse import ArgumentParser, RawDescriptionHelpFormatter, ArgumentTypeError +import psycopg2 +import getpass +import re + +class Analyser(object): + + def __init__(self, options): + password = None + if options.password_prompt: + password = getpass.getpass("Database password: ") + + self.options = options + self.conn = psycopg2.connect(dbname=options.dbname, + user=options.user, + password=password, + host=options.host, + port=options.port) + + + + def run(self): + c = self.conn.cursor() + + if self.options.placeid: + place_id = self.options.placeid + else: + if self.options.rank: + c.execute(f"""select place_id from placex + where rank_address = {self.options.rank} + and linked_place_id is null + limit 1""") + objinfo = f"rank {self.options.rank}" + + if self.options.osmid: + osm_type = self.options.osmid[0].upper() + if osm_type not in ('N', 'W', 'R'): + raise RuntimeError("OSM ID must be of form ") + try: + osm_id = int(self.options.osmid[1:]) + except ValueError: + raise RuntimeError("OSM ID must be of form ") + + c.execute(f"""SELECT place_id FROM placex + WHERE osm_type = '{osm_type}' AND osm_id = {osm_id}""") + objinfo = f"OSM object {self.options.osmid}" + + + if c.rowcount < 1: + raise RuntimeError(f"Cannot find a place for {objinfo}.") + place_id = c.fetchone()[0] + + c.execute(f"""update placex set indexed_status = 2 where + place_id = {place_id}""") + + c.execute("""SET auto_explain.log_min_duration = '0'; + SET auto_explain.log_analyze = 'true'; + SET auto_explain.log_nested_statements = 'true'; + LOAD 'auto_explain'; + SET client_min_messages = LOG; + SET log_min_messages = FATAL"""); + + c.execute(f"""update placex set indexed_status = 0 where + place_id = {place_id}""") + + c.close() # automatic rollback + + for l in self.conn.notices: + print(l) + + +if __name__ == '__main__': + def h(s): + return re.sub("\s\s+" , " ", s) + + p = ArgumentParser(description=__doc__, + formatter_class=RawDescriptionHelpFormatter) + + group = p.add_mutually_exclusive_group(required=True) + group.add_argument('--rank', dest='rank', type=int, + help='Analyse indexing of the given address rank') + group.add_argument('--osm-id', dest='osmid', type=str, + help='Analyse indexing of the given OSM object') + group.add_argument('--place-id', dest='placeid', type=int, + help='Analyse indexing of the given Nominatim object') + p.add_argument('-d', '--database', + dest='dbname', action='store', default='nominatim', + help='Name of the PostgreSQL database to connect to.') + p.add_argument('-U', '--username', + dest='user', action='store', + help='PostgreSQL user name.') + p.add_argument('-W', '--password', + dest='password_prompt', action='store_true', + help='Force password prompt.') + p.add_argument('-H', '--host', + dest='host', action='store', + help='PostgreSQL server hostname or socket location.') + p.add_argument('-P', '--port', + dest='port', action='store', + help='PostgreSQL server port') + + Analyser(p.parse_args()).run()