Skip to content

Commit 4f70c61

Browse files
authored
PG: Add per index blocks hit and blocks read (#20767)
* PG: Add per index blocks hit and blocks read pg_statio_user_indexes provides per index block usage. It is using pg_stat_get_blocks_fetched and pg_stat_get_blocks_hit behind the hood. We can emit those metrics directly from our IDX_METRICS query. The metric name index.blocks_read was used as index_blocks_read already exists for the per table block usage. * PG: Remove wal flaky tests WAL metrics presence are already covered in common pg integration tests
1 parent c79ae35 commit 4f70c61

File tree

4 files changed

+10
-71
lines changed

4 files changed

+10
-71
lines changed

postgres/changelog.d/20767.added

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PG: Add per index blocks hit and blocks read

postgres/datadog_checks/postgres/relationsmanager.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
}
6262

6363

64-
# This is similaar to pg_stat_user_indexes view
64+
# This is similar to pg_stat_user_indexes view
6565
IDX_METRICS = {
6666
'name': 'pg_index',
6767
'query': """
@@ -74,6 +74,8 @@
7474
idx_scan,
7575
idx_tup_read,
7676
idx_tup_fetch,
77+
idx_blks_read,
78+
idx_blks_hit,
7779
index_size
7880
FROM (SELECT
7981
N.nspname AS schemaname,
@@ -83,6 +85,8 @@
8385
pg_stat_get_numscans(I.oid) AS idx_scan,
8486
pg_stat_get_tuples_returned(I.oid) AS idx_tup_read,
8587
pg_stat_get_tuples_fetched(I.oid) AS idx_tup_fetch,
88+
pg_stat_get_blocks_fetched(I.oid) - pg_stat_get_blocks_hit(I.oid) AS idx_blks_read,
89+
pg_stat_get_blocks_hit(I.oid) AS idx_blks_hit,
8690
pg_relation_size(indexrelid) as index_size
8791
FROM pg_class C JOIN
8892
pg_index X ON C.oid = X.indrelid JOIN
@@ -101,6 +105,8 @@
101105
{'name': 'index_scans', 'type': 'rate'},
102106
{'name': 'index_rows_read', 'type': 'rate'},
103107
{'name': 'index_rows_fetched', 'type': 'rate'},
108+
{'name': 'index.index_blocks_read', 'type': 'rate'},
109+
{'name': 'index.index_blocks_hit', 'type': 'rate'},
104110
{'name': 'individual_index_size', 'type': 'gauge'},
105111
],
106112
}

postgres/metadata.csv

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ postgresql.function.self_time,rate,,,,"Enabled with `collect_function_metrics`.
7373
postgresql.function.total_time,rate,,,,"Enabled with `collect_function_metrics`. Total time spent in this function and all other functions called by it. This metric is tagged with db, schema, function.",0,postgres,postgres_function_total_time,,
7474
postgresql.heap_blocks_hit,gauge,,hit,second,"Enabled with `relations`. The number of buffer hits in this table. This metric is tagged with db, schema, table.",0,postgres,heap blks hit,,
7575
postgresql.heap_blocks_read,gauge,,block,second,"Enabled with `relations`. The number of disk blocks read from this table. This metric is tagged with db, schema, table.",0,postgres,heap blks read,,
76+
postgresql.index.index_blocks_hit,gauge,,hit,second,"Enabled with `relations`. The number of buffer hits for a specific index. This metric is tagged with db, schema, table, index.",0,postgres,index blks hit,,
77+
postgresql.index.index_blocks_read,gauge,,block,second,"Enabled with `relations`. The number of disk blocks for a specific index. This metric is tagged with db, schema, table, index.",0,postgres,index blks read,,
7678
postgresql.index_bloat,gauge,,percent,,"Enabled with `collect_bloat_metrics`. The estimated percentage of index bloat. This metric is tagged with db, schema, table, index.",0,postgres,ibloat,,
7779
postgresql.index_blocks_hit,gauge,,hit,second,"Enabled with `relations`. The number of buffer hits in all indexes on this table. This metric is tagged with db, schema, table.",0,postgres,idx blks hit,,
7880
postgresql.index_blocks_read,gauge,,block,second,"Enabled with `relations`. The number of disk blocks read from all indexes on this table. This metric is tagged with db, schema, table.",0,postgres,idx blks read,,

postgres/tests/test_pg_integration.py

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -605,49 +605,6 @@ def throw_exception_first_time(*args, **kwargs):
605605
assert_state_clean(check)
606606

607607

608-
@requires_over_14
609-
@pytest.mark.parametrize(
610-
'is_aurora',
611-
[True, False],
612-
)
613-
@pytest.mark.flaky(max_runs=5)
614-
def test_wal_stats(aggregator, integration_check, pg_instance, is_aurora):
615-
conn = _get_superconn(pg_instance)
616-
with conn.cursor() as cur:
617-
cur.execute("select wal_records, wal_fpi, wal_bytes from pg_stat_wal;")
618-
(wal_records, wal_fpi, wal_bytes) = cur.fetchall()[0]
619-
cur.execute("insert into persons (lastname) values ('test');")
620-
621-
# Wait for pg_stat_wal to be updated
622-
for _ in range(50):
623-
with conn.cursor() as cur:
624-
cur.execute("select wal_records, wal_bytes from pg_stat_wal;")
625-
new_wal_records = cur.fetchall()[0][0]
626-
if new_wal_records > wal_records:
627-
break
628-
time.sleep(0.1)
629-
630-
check = integration_check(pg_instance)
631-
check.is_aurora = is_aurora
632-
if is_aurora is True:
633-
return
634-
check.run()
635-
636-
expected_tags = _get_expected_tags(check, pg_instance)
637-
aggregator.assert_metric('postgresql.wal.records', count=1, tags=expected_tags)
638-
aggregator.assert_metric('postgresql.wal.bytes', count=1, tags=expected_tags)
639-
640-
# Expect at least one Heap + one Transaction additional records in the WAL
641-
assert_metric_at_least(
642-
aggregator, 'postgresql.wal.records', tags=expected_tags, count=1, lower_bound=wal_records + 2
643-
)
644-
# We should have at least one full page write
645-
assert_metric_at_least(aggregator, 'postgresql.wal.bytes', tags=expected_tags, count=1, lower_bound=wal_bytes + 100)
646-
assert_metric_at_least(
647-
aggregator, 'postgresql.wal.full_page_images', tags=expected_tags, count=1, lower_bound=wal_fpi
648-
)
649-
650-
651608
def test_query_timeout(integration_check, pg_instance):
652609
pg_instance['query_timeout'] = 1000
653610
check = integration_check(pg_instance)
@@ -658,33 +615,6 @@ def test_query_timeout(integration_check, pg_instance):
658615
cursor.execute("select pg_sleep(2000)")
659616

660617

661-
@requires_over_10
662-
@pytest.mark.parametrize(
663-
'is_aurora',
664-
[True, False],
665-
)
666-
def test_wal_metrics(aggregator, integration_check, pg_instance, is_aurora):
667-
check = integration_check(pg_instance)
668-
check.is_aurora = is_aurora
669-
670-
if is_aurora is True:
671-
return
672-
# Default PG's wal size is 16MB
673-
wal_size = 16777216
674-
675-
postgres_conn = _get_superconn(pg_instance)
676-
with postgres_conn.cursor() as cur:
677-
cur.execute("select count(*) from pg_ls_waldir();")
678-
expected_num_wals = cur.fetchall()[0][0]
679-
680-
check.run()
681-
682-
expected_wal_size = expected_num_wals * wal_size
683-
dd_agent_tags = _get_expected_tags(check, pg_instance)
684-
aggregator.assert_metric('postgresql.wal_count', count=1, value=expected_num_wals, tags=dd_agent_tags)
685-
aggregator.assert_metric('postgresql.wal_size', count=1, value=expected_wal_size, tags=dd_agent_tags)
686-
687-
688618
def test_pg_control(aggregator, integration_check, pg_instance):
689619
check = integration_check(pg_instance)
690620
check.run()

0 commit comments

Comments
 (0)