Faster DB Copies and More

tco - Copy Only What’s Needed

tco has recently been updated to allow skipping tables rarely used during development. Another change will be rolled out shortly which will make skipping various tables the default when copying to localhost. This will help safe space and time.

In an initial release, the following tables will be skipped:

  • nice_email_archive
  • nice_email_archive_to_address
  • nice_email_archive_to_email_attachment
  • nice_email_archive_to_recipient
  • nice_entity_history
  • nice_log_entry
  • nice_log_entry_var
  • nice_notification
  • nice_progress_var
  • nice_system_activity
  • nice_task_execution
  • nice_task_progress

tco will clearly indicate when tables are skipped:

$ tco cp auto master
localhost target detected: creating faster, partial, dev-only DB copy.
Creating ⚠️  partial copy ⚠️ . Will skip content of 12 tables.

Use `--show-excluded-tables` to show skipped tables. Use `--protocol
generic` to create full copy.

tco will also indicate when a partial copy is the source of a tco db-copy command:

$ tco cp /nice_master master

source:
    location: localhost/nice_master
    DB size:  0.4 GiB
    tainted: true ⚠️ (source is partial copy)
target:
    location: db5.stage.tocco.cust.vshn.net/nice_master

The same information (and more) is also shown by tco db-info:

$ tco db-info odaszh
Database main:
    server:        db1.prod.tocco.cust.vshn.net
    name:          nice_odaszh
    last modified: 2024-12-26 11:21:16 (  0 d  0 h  0 min)
    size:          7.7 GiB
    DB source / copied from:
        from:    localhost/nice_odaszh
        at:      2024-09-19 10:51:33 +02:00
        by:      jane.doe
        tainted: true ⚠️ (partial DB copy)

Database history:
    server:        db1.prod.tocco.cust.vshn.net
    name:          nice_odaszh_history
    last modified: <timeout>
    size:          7.0 GiB

See also --protocol and --exclude-table in tco cp --help output.

Skipping some of these tables (by default) for test systems is also being considered.

Thank you Stefan for the idea.

Renaming test / testold / testnew

tco has gained a new db-rename subcommand to easy renaming between the different test systems:

$ tco db-rename bbgtest bbgtestold
$ tco db-rename bbgtestnew bbgtest

This may seem rather simple but here is what how this was handled until now:

ssh ${db_server} psql postgres -c "\"ALTER DATABASE nice_${customer}test RENAME TO nice_${customer}testold\""
ssh ${db_server} psql nice_${customer}testold -c "\"REASSIGN OWNED BY nice_${customer}test TO nice_${customer}testold\""

ssh ${db_server} psql postgres -c "\"ALTER DATABASE nice_${customer}test_history RENAME TO nice_${customer}testold_history\""
ssh ${db_server} psql nice_${customer}testold_history -c "\"REASSIGN OWNED BY nice_${customer}test TO nice_${customer}testold\""

ssh ${db_server} psql postgres -c "\"ALTER DATABASE nice_${customer}testnew RENAME TO nice_${customer}test\""
ssh ${db_server} psql nice_${customer}test -c "\"REASSIGN OWNED BY nice_${customer}testnew TO nice_${customer}test\""

ssh ${db_server} psql postgres -c "\"ALTER DATABASE nice_${customer}testnew_history RENAME TO nice_${customer}test_history\""
ssh ${db_server} psql nice_${customer}test_history -c "\"REASSIGN OWNED BY nice_${customer}testnew TO nice_${customer}test\""

Warning

REASSIGN OWNED will change the owner of all objects in the DB connected to matching BY ${ROLE_NAME} and the owner of all DBs matching. Be careful when there are other DBs that have ${ROLE_NAME} as owner!

tco db-rename will do all of the above, including avoiding the pitfall mentioned in the warning, and can handle cases such as when the target DB already exists (and is empty).

Documentation will be updated to use the new command shortly, once testing has been completed.

A big thank you to Lino for pointing out that this was cumbersome and error prone.

Running SQL

This is not exactly something new but rather something others may find useful as well. tco can be used to run SQL queries stored in local files. I, for insance, have a collection of SQL scripts in ~/sql/ and then just use tco db to run them against whatever DB I need.

  1. Create an SQL file locally:

    cat > ~/sql/tables_by_size <<EOF
    SELECT n.nspname as "Schema",
      c.relname as "Name",
      CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' WHEN 'I' THEN 'partitioned index' END as "Type",
      pg_catalog.pg_get_userbyid(c.relowner) as "Owner",
      pg_catalog.pg_size_pretty(pg_catalog.pg_table_size(c.oid)) as "Size",
      pg_catalog.obj_description(c.oid, 'pg_class') as "Description"
    FROM pg_catalog.pg_class c
         LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
    WHERE c.relkind IN ('r','p','v','m','S','f','')
          AND n.nspname <> 'pg_catalog'
          AND n.nspname <> 'information_schema'
          AND n.nspname !~ '^pg_toast'
      AND pg_catalog.pg_table_is_visible(c.oid)
    ORDER BY pg_catalog.pg_table_size(c.oid) DESC, 1, 2;
    EOF
    
  2. Run it against a DB:

    $ tco db master ~/sql/tables_by_size
     Schema |                              Name                               |   Type   |    Owner    |    Size    |                                                   Description
     -------+-----------------------------------------------------------------+----------+-------------+------------+------------------------------------------------------------------------------------------------------------------
     public | nice_log_entry                                                  | table    | nice_master | 1068 MB    |
     public | nice_log_entry_var                                              | table    | nice_master | 360 MB     |
     public | nice_system_activity                                            | table    | nice_master | 67 MB      |
     public | nice_calendar_event                                             | table    | nice_master | 26 MB      |
     public | nice_incoming_payment                                           | table    | nice_master | 16 MB      |
     public | nice_reservation_registration                                   | table    | nice_master | 12 MB      |
     public | nice_task_execution                                             | table    | nice_master | 11 MB      |
    ...
    

SQL is executed by psql:

  • Any number of SQL queries can be passed at the same time.

  • Use of psql meta-commands like \x auto or \timing on in the SQL script is allowed.

    See psql(5) Meta-Commands

  • Passing arguments to psql is supported, for instance, pass -x (extended output) to psql like this: tco db <installation> <file> -- -x.

    See psql(5) OPTIONS

Example:

$ cat >~/sql/binaries <<EOF
\echo All binaries:
select current_database() as db, count(*), pg_size_pretty(coalesce(sum(size), 0)) as size from _nice_binary;

\echo Unused binaries:
select current_database() as db, count(*), pg_size_pretty(coalesce(sum(size), 0)) as size from _nice_binary where reference_count = 0;
EOF

$ tco db iffp ~/sql/binaries
All binaries:
    db     | count  | size
-----------+--------+-------
 nice_iffp | 225045 | 48 GB
(1 row)

Unused binaries:
    db     | count |  size
-----------+-------+---------
 nice_iffp | 23439 | 3945 MB
(1 row)

Updating tco

Debian / Ubuntu users will receive this updates shortly. (If not, ensure to setup the Tocco Debian Repository).

Other Linux distros and and OSes follow the instructions in the tco README file and update tco frequently.