mirror of
https://github.com/ansible/awx.git
synced 2026-10-29 22:03:20 -02:30
AAP-87549 — Add management command to create JobHostSummary composite index (#16586)
Adds `create_host_summary_index` management command that creates the composite index (host_id, id DESC) on main_jobhostsummary using CREATE INDEX CONCURRENTLY. The command is idempotent: it checks for existing valid/invalid indexes, drops invalid indexes from failed prior attempts, and skips if the index already exists. Disables statement_timeout for the session to avoid killing the index build on large tables where ALTER ROLE timeout is set. Forward-port of tower#7893 (stable-2.6). Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
7242fe89ae
commit
587b816793
@@ -0,0 +1,59 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import connection
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Creates composite index (host_id, id DESC) on main_jobhostsummary to improve host list query performance.'
|
||||
|
||||
INDEX_NAME = 'main_jobhostsumm_host_id_desc'
|
||||
TABLE_NAME = 'main_jobhostsummary'
|
||||
|
||||
def _index_status(self):
|
||||
"""Check whether the index exists in pg_class and whether it is valid.
|
||||
|
||||
Returns:
|
||||
'valid' - index exists and is usable; no action needed.
|
||||
'invalid' - index exists but was left in an invalid state by a
|
||||
previous failed CREATE INDEX CONCURRENTLY; must be
|
||||
dropped before retrying.
|
||||
None - index does not exist; safe to create.
|
||||
"""
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"SELECT pg_index.indisvalid " "FROM pg_class JOIN pg_index ON pg_class.oid = pg_index.indexrelid " "WHERE pg_class.relname = %s",
|
||||
[self.INDEX_NAME],
|
||||
)
|
||||
row = cursor.fetchone()
|
||||
if row is None:
|
||||
return None
|
||||
return 'valid' if row[0] else 'invalid'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
status = self._index_status()
|
||||
|
||||
if status == 'valid':
|
||||
self.stdout.write(f"Index {self.INDEX_NAME} already exists, nothing to do.")
|
||||
return
|
||||
|
||||
if status == 'invalid':
|
||||
self.stdout.write(f"Dropping invalid index {self.INDEX_NAME} from a previous failed attempt...")
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(f"DROP INDEX IF EXISTS {self.INDEX_NAME}")
|
||||
|
||||
self.stdout.write(f"Creating index {self.INDEX_NAME} on {self.TABLE_NAME} (host_id, id DESC) concurrently...")
|
||||
|
||||
# CREATE INDEX CONCURRENTLY cannot run inside a transaction.
|
||||
connection.ensure_connection()
|
||||
old_autocommit = connection.connection.autocommit
|
||||
connection.connection.autocommit = True
|
||||
try:
|
||||
with connection.cursor() as cursor:
|
||||
# Disable statement_timeout for this session — the customer may
|
||||
# have set ALTER ROLE ... SET statement_timeout which would kill
|
||||
# the index build on large tables.
|
||||
cursor.execute("SET statement_timeout = 0")
|
||||
cursor.execute(f"CREATE INDEX CONCURRENTLY {self.INDEX_NAME} " f"ON {self.TABLE_NAME} (host_id, id DESC)")
|
||||
finally:
|
||||
connection.connection.autocommit = old_autocommit
|
||||
|
||||
self.stdout.write(f"Index {self.INDEX_NAME} created successfully.")
|
||||
Reference in New Issue
Block a user