From c3e3296b7873534562d86e7702705fd1b222cc9c Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Thu, 21 Dec 2023 17:40:38 -0800 Subject: [PATCH] Fix very slow global introspection query when there are lots of databases (#6633) The introspection query was fetching annotations, which can never be populated on databases and which was exhibiting some pretty pathological quadratic time introspection queries. With 500 dbs, it took me about 30s. Also add a new knob to the patch system so that we can apply this in a patch without it needing to do anything expensive on each database. --- edb/schema/reflection/structure.py | 15 +++++++++++++++ edb/server/bootstrap.py | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/edb/schema/reflection/structure.py b/edb/schema/reflection/structure.py index c3f1f08e628..a21a1edc277 100644 --- a/edb/schema/reflection/structure.py +++ b/edb/schema/reflection/structure.py @@ -805,6 +805,21 @@ def generate_structure( sn.UnqualName(f'{refdict.attr}__internal'), ) + # HACK: sys::Database is an AnnotationSubject, but + # there is no way to actually put annotations on it, + # and fetching them results in some pathological + # quadratic queries where each inner iteration does + # expensive fetching of metadata and JSON decoding. + # Override it to return nothing. + # TODO: For future versions, we can probably just + # drop it. + if ( + str(rschema_name) == 'sys::Database' + and refdict.attr == 'annotations' + ): + props = {} + read_ptr = f'{read_ptr} := {{}}' + for field in props: sfn = field.sname prop_shape_els.append(f'@{sfn}') diff --git a/edb/server/bootstrap.py b/edb/server/bootstrap.py index 625167ffb7e..31764d5d954 100644 --- a/edb/server/bootstrap.py +++ b/edb/server/bootstrap.py @@ -768,6 +768,7 @@ def prepare_patch( updates: dict[str, Any] = {} global_schema_update = kind == 'ext-pkg' + sys_update_only = global_schema_update or kind.endswith('+globalonly') if kind == 'ext-pkg': # N.B: We process this without actually having the global @@ -1025,7 +1026,7 @@ def prepare_patch( # perhaps), only run the script once, on the system connection. # Since the state is global, we only should update it once. regular_updates: tuple[str, ...] - if global_schema_update: + if sys_update_only: regular_updates = (update,) sys_updates = (patch,) + sys_updates else: