Skip to content

adding drug summary table#5769

Merged
aagrawalrtsl merged 3 commits intomasterfrom
SIMPLEBACK_37_patient_prescription_summary_table
Feb 18, 2026
Merged

adding drug summary table#5769
aagrawalrtsl merged 3 commits intomasterfrom
SIMPLEBACK_37_patient_prescription_summary_table

Conversation

@aagrawalrtsl
Copy link
Contributor

Story card: sc-37

Because

Titration reports are running very slow on metabase. We need to add a table which would have monthly summary of patient's prescriptions precalculated, which can be used over metabase for faster processing.

This addresses

Adding a partitioned reporting_patient_prescriptions table which contains prescription summary for each patient every month.
Refreshing past 4 months partitions for this table, 1st of every month to account for older data syncing.

Test instructions

Connect to db console and run
CALL simple_reporting.add_shard_to_table('2026-02-01', 'reporting_patient_prescriptions');
This would populate the data for Feb-2026.
We can verify the aggregated data against prescription drugs table using sql select.

@aagrawalrtsl aagrawalrtsl requested a review from a team February 13, 2026 14:19
def up
execute <<~SQL
CREATE TABLE IF NOT EXISTS simple_reporting.reporting_patient_prescriptions (
patient_id uuid,
Copy link
Contributor

Choose a reason for hiding this comment

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

we don’t currently have indexes on:(patient_id, month_date) or month_date.Since reporting will likely filter by month and/or patient, adding these indexes will help avoid full scans and keep queries fast as data grows.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't really need a composite index on patient_id and month date.
Since the table is partitioned on month_date, postgres will prune partitions correctly when month_date is used in the filter.
But an index on patient_id is missing which I will add.

class CreateReportingPatientPrescriptions < ActiveRecord::Migration[6.1]
def up
execute <<~SQL
CREATE TABLE IF NOT EXISTS simple_reporting.reporting_patient_prescriptions (
Copy link
Contributor

Choose a reason for hiding this comment

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

We should add: PRIMARY KEY (patient_id, month_date) .This will prevent duplicate rows per patient per month and keep the data safe long-term.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This table pulls up data from reporting_patient_states which has unique patient_id and month_date record, because of distinct clause in it's definition.
Chances of getting a duplicate row per patient per month is really slim.

SQL

execute <<~SQL
CREATE INDEX index_reporting_patient_prescriptions_on_age ON ONLY simple_reporting.reporting_patient_prescriptions USING btree (age);
Copy link
Contributor

Choose a reason for hiding this comment

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

In the migration we are creating indexes like:CREATE INDEX ... ON ONLY simple_reporting.reporting_patient_prescriptions .Since this is a partitioned table, ONLY creates the index just on the parent table (which does not store any data). The actual data lives in the monthly partitions, and those partitions won’t have these indexes. That could lead to full table scans and slower reports as data grows.It would be better to remove ONLY so the indexes apply properly to the partitions as well.

Copy link
Contributor Author

@aagrawalrtsl aagrawalrtsl Feb 18, 2026

Choose a reason for hiding this comment

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

Postgres will apply the index in the partitions even if the index is created on main table and not individual partitions

explain select * from simple_reporting.reporting_patient_prescriptions where month_date = '2025-09-01' and age > 40;;
QUERY PLAN

Bitmap Heap Scan on reporting_patient_prescriptions_20250901 reporting_patient_prescriptions (cost=12.60..235.24 rows=3 width=1348)
Recheck Cond: (age > 40)
Filter: (month_date = '2025-09-01'::date)
-> Bitmap Index Scan on reporting_patient_prescriptions_20250901_age_idx (cost=0.00..12.60 rows=576 width=0)
Index Cond: (age > 40)

LEFT JOIN medicine_purposes mp ON mp.name = pd.name
WHERE pd.patient_id = rps.patient_id
AND pd.deleted_at IS NULL
AND to_char(timezone(current_setting('TIMEZONE'), timezone('UTC', pd.device_created_at)),'YYYY-MM') <= to_char(rps.month_date, 'YYYY-MM')
Copy link
Contributor

Choose a reason for hiding this comment

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

Optional: we could replace to_char() with date_trunc() and compare dates directly for cleaner and potentially more efficient date comparison.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried using date_trunc() method, but it doesn't behave efficiently over the timezone border conditions.
Although this comparison is not efficient, it is inline with the time comparison query for other reporting tables/mat views

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay

@aagrawalrtsl aagrawalrtsl merged commit 74c40cf into master Feb 18, 2026
1 check passed
@aagrawalrtsl aagrawalrtsl deleted the SIMPLEBACK_37_patient_prescription_summary_table branch February 18, 2026 10:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants