In a database, views are used as “logical tables”, exposing simplified versions of underlying base data. Views are defined by a query - the logic that turns the base data into its simplified form. In Postgres there are two types: (standard) views and materialized views.
Standard views are “live” - when you query one, the view’s defined logic is executed on the base data and results returned. A standard view always returns current data, but is subject to the execution time.
Materialized views are “static” - when a materialized view is defined, the query is executed and the results saved to disk. It’s a snapshot of the data from when the materialized view was created. So when you query a materialized view, it only reads the results from disk - this can be much faster than executing the whole query, but it needs to be refreshed periodically to collect the most recent data.
However, to change the query definition or source data of either type, you have to drop them. That’s problematic for a production database, where dropping could cause outages, downtime, etc.
So how can you change views or their sources in a production database and minimize downtime? Essentially:
Using a transaction ensures that the operation occurs atomically: any errors cause the whole operation to fail, and anyone/anything accessing the views will not notice the change.*
First, set up an original table and view:
|
|
Then, run the transaction to update the view definition:
|
|
This approach applies to any view definition update, and also to changes in source definitions themselves. When you have more than one table/view that needs to be updated (if there are multiple dependencies), repeat steps 2, 3, and 4 inside the transaction for each table/view that needs to be updated.
*I’m ignoring certain realities of read/write consistency settings, but regardless this approach minimizes surface area for the view update to impact downstream access