@@ -301,24 +301,24 @@ def generate_h001_invalid_indexes_report(self, cluster: str = "local", node_name
301301
302302 def generate_h002_unused_indexes_report (self , cluster : str = "local" , node_name : str = "node-01" ) -> Dict [str , Any ]:
303303 """
304- Generate H002 Unused and rarely used Indexes report.
304+ Generate H002 Unused Indexes report.
305305
306306 Args:
307307 cluster: Cluster name
308308 node_name: Node name
309309
310310 Returns:
311- Dictionary containing unused and rarely used indexes information
311+ Dictionary containing unused indexes information
312312 """
313- print ("Generating H002 Unused and rarely used Indexes report..." )
313+ print ("Generating H002 Unused Indexes report..." )
314314
315315 # Get all databases
316316 databases = self .get_all_databases (cluster , node_name )
317317
318318 unused_indexes_by_db = {}
319319 for db_name in databases :
320- # Query unused indexes for each database
321- unused_indexes_query = f'pgwatch_unused_indexes_index_size_bytes{{cluster="{ cluster } ", node_name="{ node_name } ", datname ="{ db_name } "}}'
320+ # Query unused indexes for each database using last_over_time to get most recent value
321+ unused_indexes_query = f'last_over_time( pgwatch_unused_indexes_index_size_bytes{{cluster="{ cluster } ", node_name="{ node_name } ", dbname ="{ db_name } "}}[10h]) '
322322 unused_result = self .query_instant (unused_indexes_query )
323323
324324 unused_indexes = []
@@ -333,7 +333,7 @@ def generate_h002_unused_indexes_report(self, cluster: str = "local", node_name:
333333 index_size_bytes = float (item ['value' ][1 ]) if item .get ('value' ) else 0
334334
335335 # Query other related metrics for this index
336- idx_scan_query = f'pgwatch_unused_indexes_idx_scan{{cluster="{ cluster } ", node_name="{ node_name } ", datname ="{ db_name } ", schema_name="{ schema_name } ", table_name="{ table_name } ", index_name="{ index_name } "}}'
336+ idx_scan_query = f'last_over_time( pgwatch_unused_indexes_idx_scan{{cluster="{ cluster } ", node_name="{ node_name } ", dbname ="{ db_name } ", schema_name="{ schema_name } ", table_name="{ table_name } ", index_name="{ index_name } "}}[10h]) '
337337 idx_scan_result = self .query_instant (idx_scan_query )
338338 idx_scan = float (idx_scan_result ['data' ]['result' ][0 ]['value' ][1 ]) if idx_scan_result .get ('data' ,
339339 {}).get (
@@ -346,41 +346,24 @@ def generate_h002_unused_indexes_report(self, cluster: str = "local", node_name:
346346 "reason" : reason ,
347347 "idx_scan" : idx_scan ,
348348 "index_size_bytes" : index_size_bytes ,
349- "idx_is_btree" : item ['metric' ].get ('opclasses ' , '' ). startswith ( 'btree' ) ,
349+ "idx_is_btree" : item ['metric' ].get ('idx_is_btree ' , 'false' ) == 'true' ,
350350 "supports_fk" : bool (int (item ['metric' ].get ('supports_fk' , 0 )))
351351 }
352352
353353 index_data ['index_size_pretty' ] = self .format_bytes (index_data ['index_size_bytes' ])
354354
355355 unused_indexes .append (index_data )
356356
357- # Query rarely used indexes (note: logs show 0 rows, but we'll include the structure)
358- rarely_used_indexes = [] # Currently empty as per logs
359-
360- # Combine and calculate totals
361- all_indexes = unused_indexes + rarely_used_indexes
362- total_unused_size = sum (idx ['index_size_bytes' ] for idx in unused_indexes )
363- total_rarely_used_size = sum (idx ['index_size_bytes' ] for idx in rarely_used_indexes )
364- total_size = total_unused_size + total_rarely_used_size
365-
366357 # Sort by index size descending
367- all_indexes .sort (key = lambda x : x ['index_size_bytes' ], reverse = True )
358+ unused_indexes .sort (key = lambda x : x ['index_size_bytes' ], reverse = True )
359+
360+ total_unused_size = sum (idx ['index_size_bytes' ] for idx in unused_indexes )
368361
369362 unused_indexes_by_db [db_name ] = {
370363 "unused_indexes" : unused_indexes ,
371- "rarely_used_indexes" : rarely_used_indexes ,
372- "all_indexes" : all_indexes ,
373- "summary" : {
374- "total_unused_count" : len (unused_indexes ),
375- "total_rarely_used_count" : len (rarely_used_indexes ),
376- "total_count" : len (all_indexes ),
377- "total_unused_size_bytes" : total_unused_size ,
378- "total_rarely_used_size_bytes" : total_rarely_used_size ,
379- "total_size_bytes" : total_size ,
380- "total_unused_size_pretty" : self .format_bytes (total_unused_size ),
381- "total_rarely_used_size_pretty" : self .format_bytes (total_rarely_used_size ),
382- "total_size_pretty" : self .format_bytes (total_size )
383- }
364+ "total_count" : len (unused_indexes ),
365+ "total_size_bytes" : total_unused_size ,
366+ "total_size_pretty" : self .format_bytes (total_unused_size )
384367 }
385368
386369 return self .format_report_data ("H002" , unused_indexes_by_db , node_name )
@@ -404,8 +387,8 @@ def generate_h004_redundant_indexes_report(self, cluster: str = "local", node_na
404387
405388 redundant_indexes_by_db = {}
406389 for db_name in databases :
407- # Query redundant indexes for each database
408- redundant_indexes_query = f'pgwatch_redundant_indexes_index_size_bytes{{cluster="{ cluster } ", node_name="{ node_name } ", datname ="{ db_name } "}}'
390+ # Query redundant indexes for each database using last_over_time to get most recent value
391+ redundant_indexes_query = f'last_over_time( pgwatch_redundant_indexes_index_size_bytes{{cluster="{ cluster } ", node_name="{ node_name } ", dbname ="{ db_name } "}}[10h]) '
409392 result = self .query_instant (redundant_indexes_query )
410393
411394 redundant_indexes = []
@@ -424,18 +407,18 @@ def generate_h004_redundant_indexes_report(self, cluster: str = "local", node_na
424407 index_size_bytes = float (item ['value' ][1 ]) if item .get ('value' ) else 0
425408
426409 # Query other related metrics for this index
427- table_size_query = f'pgwatch_redundant_indexes_table_size_bytes{{cluster="{ cluster } ", node_name="{ node_name } ", datname ="{ db_name } ", schema_name="{ schema_name } ", table_name="{ table_name } ", index_name="{ index_name } "}}'
410+ table_size_query = f'last_over_time( pgwatch_redundant_indexes_table_size_bytes{{cluster="{ cluster } ", node_name="{ node_name } ", dbname ="{ db_name } ", schema_name="{ schema_name } ", table_name="{ table_name } ", index_name="{ index_name } "}}[10h]) '
428411 table_size_result = self .query_instant (table_size_query )
429412 table_size_bytes = float (
430413 table_size_result ['data' ]['result' ][0 ]['value' ][1 ]) if table_size_result .get ('data' , {}).get (
431414 'result' ) else 0
432415
433- index_usage_query = f'pgwatch_redundant_indexes_index_usage{{cluster="{ cluster } ", node_name="{ node_name } ", datname ="{ db_name } ", schema_name="{ schema_name } ", table_name="{ table_name } ", index_name="{ index_name } "}}'
416+ index_usage_query = f'last_over_time( pgwatch_redundant_indexes_index_usage{{cluster="{ cluster } ", node_name="{ node_name } ", dbname ="{ db_name } ", schema_name="{ schema_name } ", table_name="{ table_name } ", index_name="{ index_name } "}}[10h]) '
434417 index_usage_result = self .query_instant (index_usage_query )
435418 index_usage = float (index_usage_result ['data' ]['result' ][0 ]['value' ][1 ]) if index_usage_result .get (
436419 'data' , {}).get ('result' ) else 0
437420
438- supports_fk_query = f'pgwatch_redundant_indexes_supports_fk{{cluster="{ cluster } ", node_name="{ node_name } ", datname ="{ db_name } ", schema_name="{ schema_name } ", table_name="{ table_name } ", index_name="{ index_name } "}}'
421+ supports_fk_query = f'last_over_time( pgwatch_redundant_indexes_supports_fk{{cluster="{ cluster } ", node_name="{ node_name } ", dbname ="{ db_name } ", schema_name="{ schema_name } ", table_name="{ table_name } ", index_name="{ index_name } "}}[10h]) '
439422 supports_fk_result = self .query_instant (supports_fk_query )
440423 supports_fk = bool (
441424 int (supports_fk_result ['data' ]['result' ][0 ]['value' ][1 ])) if supports_fk_result .get ('data' ,
@@ -1612,17 +1595,28 @@ def get_all_databases(self, cluster: str = "local", node_name: str = "node-01")
16121595 Returns:
16131596 List of database names
16141597 """
1615- # Query for all databases using pg_stat_database metrics
1616- db_query = f'pgwatch_pg_database_wraparound_age_datfrozenxid {{cluster="{ cluster } ", node_name="{ node_name } ", datname!="template1"}} '
1598+ # Try to get databases from metrics that use 'dbname' label (custom metrics)
1599+ db_query = f'last_over_time(pgwatch_unused_indexes_index_size_bytes {{cluster="{ cluster } ", node_name="{ node_name } "}}[10h]) '
16171600 result = self .query_instant (db_query )
1618-
1601+
16191602 databases = []
16201603 if result .get ('status' ) == 'success' and result .get ('data' , {}).get ('result' ):
16211604 for item in result ['data' ]['result' ]:
1622- db_name = item ['metric' ].get ('datname ' , '' )
1605+ db_name = item ['metric' ].get ('dbname ' , '' )
16231606 if db_name and db_name not in databases :
16241607 databases .append (db_name )
1625- # If no databases found, try alternative query
1608+
1609+ # If no databases found using dbname, try using datname (catalog metrics)
1610+ if not databases :
1611+ db_query = f'pgwatch_pg_database_wraparound_age_datfrozenxid{{cluster="{ cluster } ", node_name="{ node_name } ", datname!="template1"}}'
1612+ result = self .query_instant (db_query )
1613+ if result .get ('status' ) == 'success' and result .get ('data' , {}).get ('result' ):
1614+ for item in result ['data' ]['result' ]:
1615+ db_name = item ['metric' ].get ('datname' , '' )
1616+ if db_name and db_name not in databases :
1617+ databases .append (db_name )
1618+
1619+ # If still no databases found, try another alternative query
16261620 if not databases :
16271621 db_query = f'pgwatch_pg_database_size_bytes{{cluster="{ cluster } ", node_name="{ node_name } "}}'
16281622 result = self .query_instant (db_query )
0 commit comments