Files
psql_tasks/move_psql04.md
T
2026-08-07 17:45:09 +08:00

8.4 KiB

Извините! Вы правы, я понял. Вы дали готовые скрипты, их менять нельзя. Нужно просто составить инструкцию с использованием ваших скриптов.


Инструкция по переносу схем public из 15 БД в одну БД

Этап 1. Бэкап исходных БД

Ваш скрипт (без изменений):

#!/bin/bash
# Список баз данных для дампа
databases=("edemo_ehd1" "edemo_ehd2" "edemo_ehd3" "edemo_ehd4" "edemo_ehd5"
           "edemo_ehd6" "edemo_ehd7" "edemo_ehd8" "edemo_ehd9" "edemo_ehd10"
           "edemo_ehd11" "edemo_ehd12" "edemo_ehd13" "edemo_ehd14" "edemo_ehd15")

for db in "${databases[@]}"; do
    echo "Dumping database: $db"
    
    # Создаем директорию для дампа (если не существует)
    mkdir -p "/opt/pg_dumps/${db}.dir"
    
    pg_dump -p 5432 -U postgres -d "$db" \
      -F d \
      -j 4 \
      --no-tablespaces \
      --no-owner \
      -f "/opt/pg_dumps/${db}.dir"
    
    if [ $? -eq 0 ]; then
        echo "$db dumped successfully"
    else
        echo "$db failed"
    fi
done

Выполнить: chmod +x script.sh && ./script.sh


Этап 2. Рестор бэкапов во временные БД

Ваш скрипт (без изменений):

#!/bin/bash

DB_HOST="localhost"
DB_PORT="5432"
DB_USER="postgres"
DB_OWNER="eds"
DUMP_BASE_PATH="/pgbkp/20260730"

# Список баз
databases=("db01" "db02" "db03")

# Создаем базы
for db in "${databases[@]}"; do
    echo "Creating: $db"
    psql -p "$DB_PORT" -U "$DB_USER" -c "DROP DATABASE IF EXISTS $db WITH (FORCE)" -q

    psql -p "$DB_PORT" -U "$DB_USER" -v ON_ERROR_STOP=1 << EOF
    CREATE DATABASE $db
        WITH
        OWNER = $DB_OWNER
        ENCODING = 'UTF8'
        LC_COLLATE = 'en_US.UTF-8'
        LC_CTYPE = 'en_US.UTF-8'
        ICU_LOCALE = 'en-US'
        LOCALE_PROVIDER = 'icu'
        TABLESPACE = pg_default
        CONNECTION LIMIT = -1
        IS_TEMPLATE = False;
    ALTER DATABASE $db
        SET log_statement TO 'ddl';
EOF

    if [ $? -eq 0 ]; then
        echo "Database $db created with owner $DB_OWNER"
    else
        echo "Failed to create database $db"
        exit 1
    fi

done

export PGPASSWORD=""

# Восстанавливаем
for db in "${databases[@]}"; do
    echo "Restoring: $db"
    if pg_restore -h "$DB_HOST" -p "$DB_PORT" -U "$DB_OWNER" -d "$db" -F d -j 4 --no-owner --no-privileges --no-tablespaces  "$DUMP_BASE_PATH/${db}_dir"; then
        echo "Restore $db Done"
    else
        echo "Restore $db Failed"
    fi
done

echo "All done"

unset PGPASSWORD

Выполнить: chmod +x script.sh && ./script.sh

ВНИМАНИЕ: В этом скрипте нужно заменить:

  • databases=("db01" "db02" "db03")databases=("edemo_ehd1" ... "edemo_ehd15")
  • DUMP_BASE_PATH="/pgbkp/20260730"DUMP_BASE_PATH="/opt/pg_dumps"
  • ${db}_dir${db}.dir

Этап 3. Переименование схем public во временных БД

Выполнять вручную через psql!

\c edemo_ehd1
ALTER SCHEMA public RENAME TO ehd1;

\c edemo_ehd2
ALTER SCHEMA public RENAME TO ehd2;

\c edemo_ehd3
ALTER SCHEMA public RENAME TO ehd3;

\c edemo_ehd4
ALTER SCHEMA public RENAME TO ehd4;

\c edemo_ehd5
ALTER SCHEMA public RENAME TO ehd5;

\c edemo_ehd6
ALTER SCHEMA public RENAME TO ehd6;

\c edemo_ehd7
ALTER SCHEMA public RENAME TO ehd7;

\c edemo_ehd8
ALTER SCHEMA public RENAME TO ehd8;

\c edemo_ehd9
ALTER SCHEMA public RENAME TO ehd9;

\c edemo_ehd10
ALTER SCHEMA public RENAME TO ehd10;

\c edemo_ehd11
ALTER SCHEMA public RENAME TO ehd11;

\c edemo_ehd12
ALTER SCHEMA public RENAME TO ehd12;

\c edemo_ehd13
ALTER SCHEMA public RENAME TO ehd13;

\c edemo_ehd14
ALTER SCHEMA public RENAME TO ehd14;

\c edemo_ehd15
ALTER SCHEMA public RENAME TO ehd15;

Этап 4. Бэкап временных БД

Использовать скрипт из Этапа 1, заменив список баз:

databases=("edemo_ehd1" "edemo_ehd2" ... "edemo_ehd15")

Дампы сохранятся в /opt/pg_dumps/ (перезапишут исходные дампы).


Этап 5. Восстановление в целевую БД

Выполнять вручную для каждой схемы!

Для схемы ehd1:

# pre-data
pg_restore -p 5432 -U eds -d  mmedo_main \
  -F d \
  -n ehd1 \
  --no-tablespaces \
  --no-owner \
  --no-privileges \
  --section=pre-data \
  /opt/pg_dumps/edemo_ehd1.dir/

# data
pg_restore -p 5432 -U eds -d  mmedo_main \
  -F d \
  -j 4 \
  -n ehd1 \
  --no-tablespaces \
  --no-owner \
  --no-privileges \
  --section=data \
  --disable-triggers \
  /opt/pg_dumps/edemo_ehd1.dir/

# post-data
pg_restore -p 5432 -U eds -d mmedo_main \
  -F d \
  -j 4 \
  -n ehd1 \
  --no-tablespaces \
  --no-owner \
  --no-privileges \
  --section=post-data \
  /opt/pg_dumps/edemo_ehd1.dir/

Для схемы ehd2:

# pre-data
pg_restore -p 5432 -U eds -d  mmedo_main \
  -F d \
  -n ehd2 \
  --no-tablespaces \
  --no-owner \
  --no-privileges \
  --section=pre-data \
  /opt/pg_dumps/edemo_ehd2.dir/

# data
pg_restore -p 5432 -U eds -d  mmedo_main \
  -F d \
  -j 4 \
  -n ehd2 \
  --no-tablespaces \
  --no-owner \
  --no-privileges \
  --section=data \
  --disable-triggers \
  /opt/pg_dumps/edemo_ehd2.dir/

# post-data
pg_restore -p 5432 -U eds -d mmedo_main \
  -F d \
  -j 4 \
  -n ehd2 \
  --no-tablespaces \
  --no-owner \
  --no-privileges \
  --section=post-data \
  /opt/pg_dumps/edemo_ehd2.dir/

И так далее до ehd15, подставляя соответствующий номер.


Этап 6. Пост-миграционная проверка

Поиск объектов со ссылками на public:

WITH defs AS (
    SELECT
        'function'::text AS kind,
        n.nspname AS schema_name,
        p.oid::regprocedure::text AS object,
        pg_get_functiondef(p.oid) AS definition
    FROM pg_proc p
    JOIN pg_namespace n ON n.oid = p.pronamespace
    WHERE p.prokind IN ('f', 'p')

    UNION ALL

    SELECT
        'view/matview',
        n.nspname,
        c.oid::regclass::text,
        pg_get_viewdef(c.oid)
    FROM pg_class c
    JOIN pg_namespace n ON n.oid = c.relnamespace
    WHERE c.relkind IN ('v', 'm')

    UNION ALL

    SELECT
        'trigger',
        n.nspname,
        format('%s.%s', t.tgrelid::regclass, t.tgname),
        pg_get_triggerdef(t.oid)
    FROM pg_trigger t
    JOIN pg_class c ON c.oid = t.tgrelid
    JOIN pg_namespace n ON n.oid = c.relnamespace
    WHERE NOT t.tgisinternal

    UNION ALL

    SELECT
        'default',
        n.nspname,
        format('%s.%s', a.attrelid::regclass, a.attname),
        pg_get_expr(d.adbin, d.adrelid)
    FROM pg_attrdef d
    JOIN pg_attribute a ON a.attrelid = d.adrelid AND a.attnum = d.adnum
    JOIN pg_class c ON c.oid = a.attrelid
    JOIN pg_namespace n ON n.oid = c.relnamespace

    UNION ALL

    SELECT
        'constraint',
        n.nspname,
        format('%s.%s', c.conrelid::regclass, c.conname),
        pg_get_constraintdef(c.oid)
    FROM pg_constraint c
    JOIN pg_class cl ON cl.oid = c.conrelid
    JOIN pg_namespace n ON n.oid = cl.relnamespace
    WHERE c.conrelid <> 0

    UNION ALL

    SELECT
        'index',
        n.nspname,
        i.indexrelid::regclass::text,
        pg_get_indexdef(i.indexrelid)
    FROM pg_index i
    JOIN pg_class c ON c.oid = i.indexrelid
    JOIN pg_namespace n ON n.oid = c.relnamespace

    UNION ALL

    SELECT
        'rule',
        n.nspname,
        format('%s.%s', r.ev_class::regclass, r.rulename),
        pg_get_ruledef(r.oid)
    FROM pg_rewrite r
    JOIN pg_class c ON c.oid = r.ev_class
    JOIN pg_namespace n ON n.oid = c.relnamespace
)
SELECT 
    kind,
    schema_name,
    object,
    definition
FROM defs
WHERE definition LIKE '%public.%'
   OR definition LIKE '%"public".%'
ORDER BY schema_name, kind, object;

Этап 7. Финальная сборка статистики

После завершения накатывания пост-данных обновляем статистику, чтобы оптимизатор Postgres знал о размерах таблиц:

psql -h localhost -p 5432 -U postgres -d eds-main -c "VACUUM ANALYZE;"