What is a materialized view, and when is it worth the complexity?
A materialized view stores the result of its query as actual data. It is refreshed explicitly or on a schedule, and reading from it is a table scan or an index lookup rather than a recomputation. That is the whole trade: you give up automatic freshness and gain speed.
It is worth it when the same expensive computation is read far more often than the underlying data changes. A reporting query that joins five tables and aggregates over fifty million rows, executed once a minute for a dashboard but recomputed on every page load, is the canonical case. The dashboard reads the materialised view in milliseconds; the underlying data is at most a minute old, which nobody can observe.
It is also worth it when the query is structurally awkward to keep fast. A query with a correlated subquery over a large table, or a window function over a partition with millions of rows, can be pre-computed once and then read cheaply.
It is not worth it when the data changes constantly and the report has to be current to the second. A materialised view on a table that is written a thousand times a minute has to be refreshed constantly, and at that point the refresh cost is the same as the query cost, only paid in the background. It is also not worth it when the query is already fast — the refresh job then adds operational overhead for no gain.
One caution about staleness. A materialised view is a snapshot, and if a downstream consumer does not know the snapshot time, it can compare a figure from the materialised view with one from a live table and get a mismatch that looks like a bug. Publishing the refresh timestamp alongside the data, and making sure consumers use it consistently, is what keeps that from happening.