Skip to content

Conversation

@slardiere
Copy link
Contributor

Fix the database name lookup in the pgbouncer dashboard

  • since the metrics database model has changed, the actual database name is inside the JSON field data
  • also clean some old and unused sql queries

Sébastien Lardière and others added 4 commits October 9, 2025 15:40
    Harmonise the layout of legends: in a list and at the bottom for all signs
    since the metrics database model has changed, the actual database name is inside the JSON field data
    also clean some old and unused sql queries
@coveralls
Copy link

coveralls commented Oct 27, 2025

Pull Request Test Coverage Report for Build 19141559345

Details

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage remained the same at 71.383%

Totals Coverage Status
Change from base Build 19139967054: 0.0%
Covered Lines: 3542
Relevant Lines: 4962

💛 - Coveralls

@pashagolub
Copy link
Collaborator

Database model isn't change. :) That's something to be done with maintenance routines. Thanks! I'll check!

"metricColumn": "none",
"orderByTime": "ASC",
"policy": "default",
"query": "SELECT non_negative_derivative(mean(\"total_query_time\"), 1h) / non_negative_derivative(mean(\"total_query_count\"), 1h) FROM \"pgbouncer_stats\" WHERE \"dbname\" =~ /^$dbname$/ AND $timeFilter GROUP BY time($__interval) fill(none)",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a promQL to me. Should it be here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably a remaining query from InfluxDB

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, what an artifact! :)

@pashagolub
Copy link
Collaborator

ok, I see it. So the mess is due to terminology. In old days under "dbname" we mean the source from where we fetch metrics. But you want to have exact database on you graph.
Now, with your approach we might have a problem. What if you will have several pgbouncer sources and all of them will have databases with the same names. For example, you have test, stage, prod.
You added 3 pgbouncer sources. If now we will use your approach the data will be mixed.

So my suggestion would be to have 2 drop-downs:

  • "Monitored Source" that will filter out per-pgbouncer instance
  • "Database" that will filter per-database of per-pgbouncer (or ALL)

Does it sound right to you?

Thanks a lot for your PR!

@pashagolub pashagolub self-assigned this Oct 27, 2025
@pashagolub pashagolub added the dashboards Grafana dashboards related label Oct 27, 2025
@slardiere
Copy link
Contributor Author

Ok, I see, I'll provide that asap

@slardiere
Copy link
Contributor Author

Hi,

Do you agree with these changes? Or do you need anything else?

best regards,
Sébastien

@0xgouda
Copy link
Contributor

0xgouda commented Nov 3, 2025

Do you agree with these changes? Or do you need anything else?

We are trying to think of a way to optimize the query so we don't do a full table scan on pgbouncer_stats, which might slow down the dashboards.

@slardiere
Copy link
Contributor Author

We are trying to think of a way to optimize the query so we don't do a full table scan on pgbouncer_stats, which might slow down the dashboards.

Indeed, thanks,

I just fix the monitoredsource one, but no clue for the database one.

@0xgouda
Copy link
Contributor

0xgouda commented Nov 5, 2025

I just fix the monitoredsource one, but no clue for the database one.

Thanks!, for the dbname variable, we thought of adding $__timeFilter(time) and making the field update on every interval change, but it turns out where dbname = '$monitoredsource' already utilizes an existing "pgbouncer_stats_dbname_time_idx" btree (dbname, "time") index, so I think it's good enough.

Currently, I am trying to make the dbname multi-value field, and for each new value, new separate panels should appear for it.

@0xgouda 0xgouda force-pushed the pgbouncer-dashboard branch from 03ba19a to 20845fe Compare November 5, 2025 05:13
@0xgouda 0xgouda requested a review from pashagolub November 5, 2025 05:15
@pashagolub
Copy link
Collaborator

Thanks @0xgouda.

  1. Please include All option into $dbname
  2. Make sure all graphs are on the same panel. I don't want repeating, it produces a lot of noise. Here is the example of how it should look like:
image

@pashagolub
Copy link
Collaborator

pashagolub commented Nov 5, 2025

but it turns out where dbname = '$monitoredsource' already utilizes an existing "pgbouncer_stats_dbname_time_idx" btree (dbname, "time") index, so I think it's good enough.

Well, I cannot confirm that:

pgwatch_metrics=# explain analyze select distinct (data->>'database') as database from pgbouncer_stats where dbname = 'demo_pgbouncer';
                                                                                  QUERY PLAN                                                                                   
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=67.47..69.33 rows=149 width=32) (actual time=1.533..1.537 rows=2.00 loops=1)
   Group Key: ((pgbouncer_stats.data ->> 'database'::text))
   Batches: 1  Memory Usage: 32kB
   Buffers: shared hit=7 read=27 dirtied=1
   I/O Timings: shared read=0.831
   ->  Append  (cost=0.00..66.83 rows=255 width=32) (actual time=0.331..1.470 rows=251.00 loops=1)
         Buffers: shared hit=7 read=27 dirtied=1
         I/O Timings: shared read=0.831
         ->  Seq Scan on pgbouncer_stats_demo_pgbouncer_y2025w45 pgbouncer_stats_1  (cost=0.00..31.69 rows=246 width=32) (actual time=0.330..1.415 rows=251.00 loops=1)
               Filter: (dbname = 'demo_pgbouncer'::text)
               Buffers: shared hit=1 read=27 dirtied=1
               I/O Timings: shared read=0.831
         ->  Bitmap Heap Scan on pgbouncer_stats_demo_pgbouncer_y2025w46 pgbouncer_stats_2  (cost=4.17..11.29 rows=3 width=32) (actual time=0.010..0.010 rows=0.00 loops=1)
               Recheck Cond: (dbname = 'demo_pgbouncer'::text)
               Buffers: shared hit=2
               ->  Bitmap Index Scan on pgbouncer_stats_demo_pgbouncer_y2025w46_dbname_time_idx  (cost=0.00..4.17 rows=3 width=0) (actual time=0.005..0.006 rows=0.00 loops=1)
                     Index Cond: (dbname = 'demo_pgbouncer'::text)
                     Index Searches: 1
                     Buffers: shared hit=2
         ->  Bitmap Heap Scan on pgbouncer_stats_demo_pgbouncer_y2025w47 pgbouncer_stats_3  (cost=4.17..11.29 rows=3 width=32) (actual time=0.004..0.005 rows=0.00 loops=1)
               Recheck Cond: (dbname = 'demo_pgbouncer'::text)
               Buffers: shared hit=2
               ->  Bitmap Index Scan on pgbouncer_stats_demo_pgbouncer_y2025w47_dbname_time_idx  (cost=0.00..4.17 rows=3 width=0) (actual time=0.002..0.002 rows=0.00 loops=1)
                     Index Cond: (dbname = 'demo_pgbouncer'::text)
                     Index Searches: 1
                     Buffers: shared hit=2
         ->  Bitmap Heap Scan on pgbouncer_stats_demo_pgbouncer_y2025w48 pgbouncer_stats_4  (cost=4.17..11.29 rows=3 width=32) (actual time=0.011..0.012 rows=0.00 loops=1)
               Recheck Cond: (dbname = 'demo_pgbouncer'::text)
               Buffers: shared hit=2
               ->  Bitmap Index Scan on pgbouncer_stats_demo_pgbouncer_y2025w48_dbname_time_idx  (cost=0.00..4.17 rows=3 width=0) (actual time=0.004..0.005 rows=0.00 loops=1)
                     Index Cond: (dbname = 'demo_pgbouncer'::text)
                     Index Searches: 1
                     Buffers: shared hit=2
 Planning:
   Buffers: shared hit=3
 Planning Time: 0.311 ms
 Execution Time: 1.719 ms
(37 rows)

Index is used for panels but not for variable refresh. As you can see we need to check all partitions.

- all lines appear within the same panel.
- add `all` field to the `DB Name` multi-value.
- to avoid confustion the queries already have `dbname` column
@slardiere
Copy link
Contributor Author

slardiere commented Nov 5, 2025

Ok for selecting multiples values, but you need to change the SQL query with the database field in the window definition.

For the stat panels, perhaps use the sum of the values for the selected databases, instead of the repetitive panel, which I do not find very aesthetically pleasing. I can fix it if you agree.

    prevent scanning all partitions
@slardiere
Copy link
Contributor Author

Indeed, adding time filter in the database selector use index : 

explain (analyse) select distinct (data->>'database') as database from pgbouncer_stats where dbname = 'pgb_spokane'   and time BETWEEN '2025-11-05T09:52:10.401Z' AND '2025-11-05T15:52:10.401Z' ;
                                                                                                           QUERY PLAN                                                                                              
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=2552.06..2554.56 rows=200 width=32) (actual time=24.718..24.721 rows=5.00 loops=1)
   Group Key: (pgbouncer_stats.data ->> 'database'::text)
   Batches: 1  Memory Usage: 32kB
   Buffers: shared hit=1223
   ->  Index Scan using pgbouncer_stats_pgb_spokane_y2025w45_dbname_time_idx on pgbouncer_stats_pgb_spokane_y2025w45 pgbouncer_stats  (cost=0.29..2539.14 rows=5168 width=32) (actual time=0.121..19.925 rows=10795
         Index Cond: ((dbname = 'pgb_spokane'::text) AND ("time" >= '2025-11-05 10:52:10.401+01'::timestamp with time zone) AND ("time" <= '2025-11-05 16:52:10.401+01'::timestamp with time zone))
         Index Searches: 1
         Buffers: shared hit=1223
 Planning Time: 0.371 ms
 Execution Time: 24.763 ms

Copy link
Contributor

@0xgouda 0xgouda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update dynamically on time range change.

update dynamically on time range change

Co-authored-by: Ahmed Gouda <gouda0x@gmail.com>
@pashagolub
Copy link
Collaborator

@slardiere would you please check the stats panels if they work for you? I'm fine with whatever option.

Copy link
Collaborator

@pashagolub pashagolub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job @0xgouda! Thanks!

@pashagolub pashagolub changed the title Fix Pgbouncer dashboard [-] fix pgbouncer dashboard Nov 6, 2025
@slardiere
Copy link
Contributor Author

@slardiere would you please check the stats panels if they work for you? I'm fine with whatever option.

@pashagolub yes, stats panels works for me, it's ok

@pashagolub pashagolub merged commit 45a761c into cybertec-postgresql:master Nov 7, 2025
5 checks passed
@slardiere slardiere deleted the pgbouncer-dashboard branch November 7, 2025 11:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dashboards Grafana dashboards related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants