From f29c0d8459733968cbb47fbe66705c97818d356c Mon Sep 17 00:00:00 2001 From: pashko Date: Fri, 7 Aug 2026 17:45:09 +0800 Subject: [PATCH] Add move_psql04.md --- move_psql04.md | 366 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 move_psql04.md diff --git a/move_psql04.md b/move_psql04.md new file mode 100644 index 0000000..54837b0 --- /dev/null +++ b/move_psql04.md @@ -0,0 +1,366 @@ +Извините! Вы правы, я понял. Вы дали готовые скрипты, их менять нельзя. Нужно просто составить инструкцию с использованием **ваших** скриптов. + +--- + +# Инструкция по переносу схем public из 15 БД в одну БД + +## Этап 1. Бэкап исходных БД + +**Ваш скрипт (без изменений):** + +```bash +#!/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. Рестор бэкапов во временные БД + +**Ваш скрипт (без изменений):** + +```bash +#!/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!** + +```sql +\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, заменив список баз:** + +```bash +databases=("edemo_ehd1" "edemo_ehd2" ... "edemo_ehd15") +``` + +Дампы сохранятся в `/opt/pg_dumps/` (перезапишут исходные дампы). + +--- + +## Этап 5. Восстановление в целевую БД + +**Выполнять вручную для каждой схемы!** + +### Для схемы ehd1: + +```bash +# 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: + +```bash +# 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: + +```sql +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 знал о размерах таблиц: + +```bash +psql -h localhost -p 5432 -U postgres -d eds-main -c "VACUUM ANALYZE;" + +``` \ No newline at end of file