From 779ec6c3f67428f3529cdd2a98867684b8dc20be Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Fri, 24 Jul 2020 13:53:59 +0200 Subject: [PATCH] Metrics: Return accurate counts for less interesting models --- doc/admin/maintainance.rst | 3 ++- src/pretix/base/metrics.py | 24 +++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/doc/admin/maintainance.rst b/doc/admin/maintainance.rst index bc7051a72c..f035874662 100644 --- a/doc/admin/maintainance.rst +++ b/doc/admin/maintainance.rst @@ -92,7 +92,8 @@ pretix_task_duration_seconds pretix_model_instances Gauge. Measures number of instances of a certain model within the database, labeled with - the ``model`` name. + the ``model`` name. Starting with pretix 3.11, these numbers might only be approximate for + most tables when running on PostgreSQL to mitigate performance impact. .. _metric types: https://prometheus.io/docs/concepts/metric_types/ .. _Prometheus: https://prometheus.io/ diff --git a/src/pretix/base/metrics.py b/src/pretix/base/metrics.py index 22e56d3ba5..4b2afa9d3c 100755 --- a/src/pretix/base/metrics.py +++ b/src/pretix/base/metrics.py @@ -3,6 +3,9 @@ from collections import defaultdict from django.apps import apps from django.conf import settings +from django.db import connection + +from pretix.base.models import Event, Invoice, Order, OrderPosition, Organizer if settings.HAS_REDIS: import django_redis @@ -201,6 +204,19 @@ class Histogram(Metric): self._execute_redis_pipeline(pipe) +def estimate_count_fast(type): + """ + See https://wiki.postgresql.org/wiki/Count_estimate + """ + if 'postgres' in settings.DATABASES['default']['ENGINE']: + cursor = connection.cursor() + cursor.execute("select reltuples from pg_class where relname='%s';" % type._meta.db_table) + row = cursor.fetchone() + return int(row[0]) + else: + return type.objects.count() + + def metric_values(): """ Produces the the values to be presented to the monitoring system @@ -223,8 +239,14 @@ def metric_values(): metrics[a] = metrics[atarget] # Throwaway metrics + exact_tables = [ + Order, OrderPosition, Invoice, Event, Organizer + ] for m in apps.get_models(): # Count all models - metrics['pretix_model_instances']['{model="%s"}' % m._meta] = m.objects.count() + if any(issubclass(m, p) for p in exact_tables): + metrics['pretix_model_instances']['{model="%s"}' % m._meta] = m.objects.count() + else: + metrics['pretix_model_instances']['{model="%s"}' % m._meta] = estimate_count_fast(m) return metrics