3

I have a very central table in our database that is used by a range of applications, it has rules attached to it, triggers and all the dependencies that you can imagine. Now I would like to modify the table without causing any problems with the dependencies. I have previously been successful with doing the following but in a much less complex case:

alter table reconciliations rename to matches;
create view reconciliations as select * from matches;

What this achieves is that I could now modify the new "matches" table and for example add a column or rows, which do not need to get presented in the "reconciliations" view (by adding a where clause to filter them out).

I am on Postgres 9.5 so the view is automatically updatable. Initial tests shows that there are no immediate problems with this, so I am asking this question to know what kind of problems I should be looking for. Performance is not a big issue.

  • If the original reconciliations view is reading from matches. then just modify matches directly in a transaction. You don't need to create a new table for that, unless your view uses select * in which case, fix your view then modify matches: BEGIN; ALTER.. ALTER.. ALTER.. COMMIT; – Evan Carroll Jan 17 '17 at 12:18
  • The original "reconciliations" is a table which I convert to a view, which writes to the "matches" table. I use views as an abstraction layer. – David Jan 17 '17 at 12:47
6

If you do this in production, be aware of prepared statements. Those have already been parsed, rewritten (and the query plan cached). The effect kicks until prepared statements are deallocated (which can take a long time).

To check for prepared statements (of the same session only!):

TABLE pg_prepared_statements;

The effect also extends to plpgsql functions that handle SQL commands like prepared statements internally.

Normally, prepared statements are forced to be re-planned after any change to involved objects. But your actions circumvent this security mechanism.

Also, most queries will just keep working. But not all.

Demo

CREATE TEMP TABLE foo (id int);
INSERT INTO foo VALUES (4);
PREPARE x AS SELECT foo FROM foo WHERE id > $1;  -- uses row type

This works:

ALTER TABLE foo ADD COLUMN t text;
EXECUTE x(3);  -- automatically re-planned

But this does not:

ALTER TABLE foo RENAME TO foo1;
CREATE VIEW foo AS TABLE foo1;
ALTER TABLE foo1 ADD COLUMN t text;

EXECUTE x(3);  -- not re-planned!
ERROR:  cached plan must not change result type

The manual on PREPARE:

Although the main point of a prepared statement is to avoid repeated parse analysis and planning of the statement, PostgreSQL will force re-analysis and re-planning of the statement before using it whenever database objects used in the statement have undergone definitional (DDL) changes since the previous use of the prepared statement. Also, if the value of search_path changes from one use to the next, the statement will be re-parsed using the new search_path. (This latter behavior is new as of PostgreSQL 9.3.) These rules make use of a prepared statement semantically almost equivalent to re-submitting the same query text over and over, but with a performance benefit if no object definitions are changed, especially if the best plan remains the same across uses. An example of a case where the semantic equivalence is not perfect is that if the statement refers to a table by an unqualified name, and then a new table of the same name is created in a schema appearing earlier in the search_path, no automatic re-parse will occur since no object used in the statement changed. However, if some other change forces a re-parse, the new table will be referenced in subsequent uses.

The above is another example where the "semantic equivalence is not perfect".

  • Excellent point! Do you see any other problems with replacing a table with a view like this? – David Jan 18 '17 at 11:27
  • 1
    @David: I have done it before and don't see any other immediate problems - which doesn't mean there are none. It's a piece of complication and complications lead to problems ... – Erwin Brandstetter Jan 19 '17 at 1:55
  • I really appreciate your help! Do you have any thoughts on the two ideas for solving the same problem that I introduced here: dba.stackexchange.com/questions/161720/… I am primarily interested in the creating of aliases and depreciation of old names. I don't know how to do this for tables on Postgres. – David Jan 20 '17 at 8:17
  • Also I'd like to point out that any views referencing original table would still reference the same (renamed to "matches") table and not the new view "reconciliations" – dmikam Oct 29 '18 at 11:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.