Update move_psql01.md
This commit is contained in:
@@ -1,17 +0,0 @@
|
|||||||
## Этап 1. Создание дампов
|
|
||||||
### 1.1. Дамп СХЕМЫ (только таблицы, без функций/триггеров)
|
|
||||||
```shell
|
|
||||||
pg_dump -p 5436 -U postgres -d edemo_ehd1 \
|
|
||||||
--schema-only \
|
|
||||||
--clean \
|
|
||||||
--if-exists \
|
|
||||||
--exclude-function \
|
|
||||||
--exclude-trigger \
|
|
||||||
--exclude-table="*" \
|
|
||||||
--exclude-schema=pg_catalog,information_schema \
|
|
||||||
2>/dev/null | \
|
|
||||||
grep -vE '^(CREATE|ALTER|DROP) (ROLE|TABLESPACE)' | \
|
|
||||||
sed -E 's/OWNER TO [^;]+;/OWNER TO current_user;/g' | \
|
|
||||||
sed -E 's/ TABLESPACE = [^;]+//g' \
|
|
||||||
> /opt/pg_dumps/01_schema_tables.sql
|
|
||||||
```
|
|
||||||
+460
@@ -0,0 +1,460 @@
|
|||||||
|
- **Смена tablespace** с кастомного на дефолтный
|
||||||
|
- **Удаление OWNER** (замена на `current_user`)
|
||||||
|
- **Удаление ROLE/TABLESPACE** из дампа
|
||||||
|
- **Разделение по типам объектов**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Этап 1. Создание дампов
|
||||||
|
|
||||||
|
### 1.1. Дамп СХЕМЫ (только таблицы, без функций/триггеров)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pg_dump -p 5436 -U postgres -d edemo_ehd1 \
|
||||||
|
--schema-only \
|
||||||
|
--clean \
|
||||||
|
--if-exists \
|
||||||
|
--exclude-function \
|
||||||
|
--exclude-trigger \
|
||||||
|
--exclude-table="*" \
|
||||||
|
--exclude-schema=pg_catalog,information_schema \
|
||||||
|
2>/dev/null | \
|
||||||
|
grep -vE '^(CREATE|ALTER|DROP) (ROLE|TABLESPACE)' | \
|
||||||
|
sed -E 's/OWNER TO [^;]+;/OWNER TO current_user;/g' | \
|
||||||
|
sed -E 's/ TABLESPACE = [^;]+//g' \
|
||||||
|
> /opt/pg_dumps/01_schema_tables.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
**Что делает:**
|
||||||
|
- `--schema-only` — только структура
|
||||||
|
- `--clean --if-exists` — DROP IF EXISTS перед созданием
|
||||||
|
- `--exclude-function --exclude-trigger` — исключаем функции и триггеры
|
||||||
|
- `grep -vE` — удаляем строки с ROLE и TABLESPACE
|
||||||
|
- `sed` — меняем OWNER на current_user и удаляем TABLESPACE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.2. Дамп ДАННЫХ (без схемы, с отключенными триггерами)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pg_dump -p 5436 -U postgres -d edemo_ehd1 \
|
||||||
|
--data-only \
|
||||||
|
--disable-triggers \
|
||||||
|
--no-owner \
|
||||||
|
--no-privileges \
|
||||||
|
-F c \
|
||||||
|
-f /opt/pg_dumps/02_data.dump
|
||||||
|
```
|
||||||
|
|
||||||
|
**Что делает:**
|
||||||
|
- `--data-only` — только данные
|
||||||
|
- `--disable-triggers` — отключаем триггеры при дампе
|
||||||
|
- `--no-owner` — не сохраняем владельцев
|
||||||
|
- `-F c` — кастомный формат (для скорости)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.3. Дамп ФУНКЦИЙ И ПРОЦЕДУР
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pg_dump -p 5436 -U postgres -d edemo_ehd1 \
|
||||||
|
--schema-only \
|
||||||
|
--clean \
|
||||||
|
--if-exists \
|
||||||
|
--function \
|
||||||
|
--procedure \
|
||||||
|
2>/dev/null | \
|
||||||
|
grep -vE '^(CREATE|ALTER|DROP) (ROLE|TABLESPACE)' | \
|
||||||
|
sed -E 's/OWNER TO [^;]+;/OWNER TO current_user;/g' | \
|
||||||
|
sed -E 's/ TABLESPACE = [^;]+//g' \
|
||||||
|
> /opt/pg_dumps/03_functions.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
**Что делает:**
|
||||||
|
- `--function --procedure` — выгружаем только функции и процедуры
|
||||||
|
- Остальное аналогично пункту 1.1
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.4. Дамп ТРИГГЕРОВ
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pg_dump -p 5436 -U postgres -d edemo_ehd1 \
|
||||||
|
--schema-only \
|
||||||
|
--clean \
|
||||||
|
--if-exists \
|
||||||
|
--trigger \
|
||||||
|
2>/dev/null | \
|
||||||
|
grep -vE '^(CREATE|ALTER|DROP) (ROLE|TABLESPACE)' | \
|
||||||
|
sed -E 's/OWNER TO [^;]+;/OWNER TO current_user;/g' | \
|
||||||
|
sed -E 's/ TABLESPACE = [^;]+//g' \
|
||||||
|
> /opt/pg_dumps/04_triggers.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.5. Дамп ПРЕДСТАВЛЕНИЙ (VIEWS)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Полный дамп схемы
|
||||||
|
pg_dump -p 5436 -U postgres -d edemo_ehd1 \
|
||||||
|
--schema-only \
|
||||||
|
--clean \
|
||||||
|
--if-exists \
|
||||||
|
2>/dev/null | \
|
||||||
|
grep -vE '^(CREATE|ALTER|DROP) (ROLE|TABLESPACE)' | \
|
||||||
|
sed -E 's/OWNER TO [^;]+;/OWNER TO current_user;/g' | \
|
||||||
|
sed -E 's/ TABLESPACE = [^;]+//g' \
|
||||||
|
> /opt/pg_dumps/05_full_schema_clean.sql
|
||||||
|
|
||||||
|
# Извлекаем только VIEWS
|
||||||
|
grep -E 'CREATE (OR REPLACE )?VIEW' /opt/pg_dumps/05_full_schema_clean.sql \
|
||||||
|
> /opt/pg_dumps/05_views.sql
|
||||||
|
|
||||||
|
# Удаляем временный файл
|
||||||
|
rm -f /opt/pg_dumps/05_full_schema_clean.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.6. (Опционально) Дамп ВНЕШНИХ КЛЮЧЕЙ (если нужно создавать отдельно)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pg_dump -p 5436 -U postgres -d edemo_ehd1 \
|
||||||
|
--schema-only \
|
||||||
|
--clean \
|
||||||
|
--if-exists \
|
||||||
|
--constraint \
|
||||||
|
2>/dev/null | \
|
||||||
|
grep -vE '^(CREATE|ALTER|DROP) (ROLE|TABLESPACE)' | \
|
||||||
|
sed -E 's/OWNER TO [^;]+;/OWNER TO current_user;/g' | \
|
||||||
|
sed -E 's/ TABLESPACE = [^;]+//g' \
|
||||||
|
> /opt/pg_dumps/06_constraints.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Этап 2. Восстановление в целевой БД
|
||||||
|
|
||||||
|
### 2.0. Подготовка целевой БД
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Параметры
|
||||||
|
NEW_HOST="new_host"
|
||||||
|
USER="postgres"
|
||||||
|
NEW_DB="new_db"
|
||||||
|
|
||||||
|
# Создаем БД (если не существует)
|
||||||
|
createdb -h $NEW_HOST -U $USER $NEW_DB
|
||||||
|
|
||||||
|
# Или пересоздаем
|
||||||
|
dropdb -h $NEW_HOST -U $USER --if-exists $NEW_DB
|
||||||
|
createdb -h $NEW_HOST -U $USER $NEW_DB
|
||||||
|
|
||||||
|
# Убеждаемся, что используется дефолтный tablespace
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB -c "SHOW default_tablespace;"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.1. Восстановление ТАБЛИЦ (схема)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "=== ШАГ 2.1: Восстановление таблиц ==="
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB -f /opt/pg_dumps/01_schema_tables.sql
|
||||||
|
|
||||||
|
# Проверяем
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB -c "\dt" | head -20
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ожидаемый результат:** Все таблицы созданы, без функций и триггеров.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.2. Восстановление ДАННЫХ
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "=== ШАГ 2.2: Восстановление данных ==="
|
||||||
|
pg_restore -h $NEW_HOST -U $USER -d $NEW_DB \
|
||||||
|
--data-only \
|
||||||
|
--disable-triggers \
|
||||||
|
--no-owner \
|
||||||
|
--no-privileges \
|
||||||
|
-j 1 \
|
||||||
|
/opt/pg_dumps/02_data.dump
|
||||||
|
|
||||||
|
# Проверяем количество записей
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB -c "
|
||||||
|
SELECT schemaname, tablename, n_live_tup
|
||||||
|
FROM pg_stat_user_tables
|
||||||
|
WHERE schemaname = 'public'
|
||||||
|
ORDER BY n_live_tup DESC
|
||||||
|
LIMIT 10;"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ожидаемый результат:** Данные залиты, триггеры не срабатывали.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.3. Восстановление ФУНКЦИЙ И ПРОЦЕДУР
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "=== ШАГ 2.3: Восстановление функций и процедур ==="
|
||||||
|
|
||||||
|
# Проверяем, есть ли уже функции
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB <<EOF
|
||||||
|
SELECT proname, pronargs
|
||||||
|
FROM pg_proc
|
||||||
|
WHERE pronamespace::regnamespace::text = 'public'
|
||||||
|
ORDER BY proname;
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Восстанавливаем
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB -f /opt/pg_dumps/03_functions.sql
|
||||||
|
|
||||||
|
# Если ошибка "already exists", добавляем OR REPLACE
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "⚠️ Ошибка, пробуем с CREATE OR REPLACE..."
|
||||||
|
sed -i.bak 's/CREATE FUNCTION/CREATE OR REPLACE FUNCTION/g' /opt/pg_dumps/03_functions.sql
|
||||||
|
sed -i.bak 's/CREATE PROCEDURE/CREATE OR REPLACE PROCEDURE/g' /opt/pg_dumps/03_functions.sql
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB -f /opt/pg_dumps/03_functions.sql
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Проверяем
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB -c "
|
||||||
|
SELECT proname, pronargs
|
||||||
|
FROM pg_proc
|
||||||
|
WHERE pronamespace::regnamespace::text = 'public'
|
||||||
|
ORDER BY proname;"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ожидаемый результат:** Все функции созданы корректно.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.4. Восстановление ТРИГГЕРОВ
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "=== ШАГ 2.4: Восстановление триггеров ==="
|
||||||
|
|
||||||
|
# Удаляем существующие триггеры (если есть)
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB <<EOF
|
||||||
|
DO \$\$
|
||||||
|
DECLARE
|
||||||
|
r RECORD;
|
||||||
|
BEGIN
|
||||||
|
FOR r IN
|
||||||
|
SELECT tgname, tgrelid::regclass::text as table_name
|
||||||
|
FROM pg_trigger
|
||||||
|
WHERE tgisinternal = false
|
||||||
|
AND tgrelid::regclass::text LIKE 'public.%'
|
||||||
|
LOOP
|
||||||
|
EXECUTE format('DROP TRIGGER IF EXISTS %I ON %s;', r.tgname, r.table_name);
|
||||||
|
END LOOP;
|
||||||
|
END \$\$;
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Восстанавливаем триггеры
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB -f /opt/pg_dumps/04_triggers.sql
|
||||||
|
|
||||||
|
# Проверяем
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB -c "
|
||||||
|
SELECT
|
||||||
|
tgname as trigger_name,
|
||||||
|
tgrelid::regclass::text as table_name,
|
||||||
|
tgfoid::regproc as function_name
|
||||||
|
FROM pg_trigger
|
||||||
|
WHERE tgisinternal = false
|
||||||
|
AND tgrelid::regclass::text LIKE 'public.%'
|
||||||
|
ORDER BY tgname;"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ожидаемый результат:** Триггеры созданы, но пока отключены (или включены, зависит от дампа).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.5. Восстановление ПРЕДСТАВЛЕНИЙ (VIEWS)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "=== ШАГ 2.5: Восстановление представлений ==="
|
||||||
|
|
||||||
|
# Проверяем, есть ли уже представления
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB -c "\dv"
|
||||||
|
|
||||||
|
# Восстанавливаем
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB -f /opt/pg_dumps/05_views.sql
|
||||||
|
|
||||||
|
# Проверяем
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB -c "
|
||||||
|
SELECT schemaname, viewname
|
||||||
|
FROM pg_views
|
||||||
|
WHERE schemaname = 'public'
|
||||||
|
ORDER BY viewname;"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ожидаемый результат:** Все представления созданы.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.6. ВКЛЮЧАЕМ ТРИГГЕРЫ
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "=== ШАГ 2.6: Включение триггеров ==="
|
||||||
|
|
||||||
|
# Включаем триггеры
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB -c "SET session_replication_role = 'origin';"
|
||||||
|
|
||||||
|
# Проверяем статус триггеров
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB -c "
|
||||||
|
SELECT
|
||||||
|
tgname as trigger_name,
|
||||||
|
tgrelid::regclass::text as table_name,
|
||||||
|
CASE tgenabled
|
||||||
|
WHEN 'O' THEN '✅ ON (включен)'
|
||||||
|
WHEN 'D' THEN '❌ DISABLED (отключен)'
|
||||||
|
WHEN 'R' THEN '🔄 REPLICA'
|
||||||
|
WHEN 'A' THEN '🔄 ALWAYS'
|
||||||
|
END as status
|
||||||
|
FROM pg_trigger
|
||||||
|
WHERE tgisinternal = false
|
||||||
|
AND tgrelid::regclass::text LIKE 'public.%'
|
||||||
|
ORDER BY tgname;"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ожидаемый результат:** Все триггеры включены (status = ON).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Этап 3. Проверка целостности
|
||||||
|
|
||||||
|
### 3.1. Проверка внешних ключей
|
||||||
|
|
||||||
|
```bash
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB <<EOF
|
||||||
|
DO \$\$
|
||||||
|
DECLARE
|
||||||
|
r RECORD;
|
||||||
|
v_count BIGINT;
|
||||||
|
v_error_count INT := 0;
|
||||||
|
BEGIN
|
||||||
|
RAISE NOTICE '=== ПРОВЕРКА ВНЕШНИХ КЛЮЧЕЙ ===';
|
||||||
|
|
||||||
|
FOR r IN
|
||||||
|
SELECT
|
||||||
|
tc.table_schema,
|
||||||
|
tc.table_name,
|
||||||
|
tc.constraint_name,
|
||||||
|
ccu.table_name as fk_table
|
||||||
|
FROM information_schema.table_constraints tc
|
||||||
|
JOIN information_schema.constraint_column_usage ccu
|
||||||
|
ON ccu.constraint_name = tc.constraint_name
|
||||||
|
WHERE constraint_type = 'FOREIGN KEY'
|
||||||
|
AND tc.table_schema = 'public'
|
||||||
|
LOOP
|
||||||
|
EXECUTE format(
|
||||||
|
'SELECT COUNT(*) FROM %I.%I WHERE NOT EXISTS (SELECT 1 FROM %I.%I)',
|
||||||
|
r.table_schema, r.table_name, r.table_schema, r.fk_table
|
||||||
|
) INTO v_count;
|
||||||
|
|
||||||
|
IF v_count > 0 THEN
|
||||||
|
RAISE NOTICE '⚠️ %: % сиротских записей (ссылаются на %)',
|
||||||
|
r.constraint_name, v_count, r.fk_table;
|
||||||
|
v_error_count := v_error_count + 1;
|
||||||
|
END IF;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
IF v_error_count = 0 THEN
|
||||||
|
RAISE NOTICE '✅ Все внешние ключи корректны!';
|
||||||
|
ELSE
|
||||||
|
RAISE NOTICE '❌ Найдено проблем: %', v_error_count;
|
||||||
|
END IF;
|
||||||
|
END \$\$;
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3.2. Проверка работы триггеров
|
||||||
|
|
||||||
|
```bash
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB <<EOF
|
||||||
|
-- Проверяем, что триггеры активны
|
||||||
|
SELECT
|
||||||
|
tgname,
|
||||||
|
tgenabled,
|
||||||
|
tgfoid::regproc as function_name
|
||||||
|
FROM pg_trigger
|
||||||
|
WHERE tgisinternal = false
|
||||||
|
AND tgenabled IN ('O', 'A') -- ON или ALWAYS
|
||||||
|
AND tgrelid::regclass::text LIKE 'public.%';
|
||||||
|
|
||||||
|
-- Тестовый INSERT для проверки триггера (замените на вашу таблицу)
|
||||||
|
-- BEGIN;
|
||||||
|
-- INSERT INTO public."EdsDocumentModelTask" (...) VALUES (...);
|
||||||
|
-- SELECT * FROM public."BarcodeOldBarcodePair" WHERE ...;
|
||||||
|
-- ROLLBACK;
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3.3. Итоговая проверка
|
||||||
|
|
||||||
|
```bash
|
||||||
|
psql -h $NEW_HOST -U $USER -d $NEW_DB <<EOF
|
||||||
|
\echo '=== ОБЩАЯ СТАТИСТИКА ==='
|
||||||
|
|
||||||
|
-- Количество таблиц
|
||||||
|
SELECT 'Таблицы: ' || count(*) as info
|
||||||
|
FROM pg_tables
|
||||||
|
WHERE schemaname = 'public';
|
||||||
|
|
||||||
|
-- Количество функций
|
||||||
|
SELECT 'Функции: ' || count(*) as info
|
||||||
|
FROM pg_proc
|
||||||
|
WHERE pronamespace::regnamespace::text = 'public';
|
||||||
|
|
||||||
|
-- Количество триггеров
|
||||||
|
SELECT 'Триггеры: ' || count(*) as info
|
||||||
|
FROM pg_trigger
|
||||||
|
WHERE tgisinternal = false
|
||||||
|
AND tgrelid::regclass::text LIKE 'public.%';
|
||||||
|
|
||||||
|
-- Количество представлений
|
||||||
|
SELECT 'Представления: ' || count(*) as info
|
||||||
|
FROM pg_views
|
||||||
|
WHERE schemaname = 'public';
|
||||||
|
|
||||||
|
-- Размер БД
|
||||||
|
SELECT pg_size_pretty(pg_database_size(current_database())) as db_size;
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Итоговый список файлов
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/opt/pg_dumps/
|
||||||
|
├── 01_schema_tables.sql # Только таблицы (+ индексы, PK)
|
||||||
|
├── 02_data.dump # Данные (кастомный формат)
|
||||||
|
├── 03_functions.sql # Функции и процедуры
|
||||||
|
├── 04_triggers.sql # Триггеры
|
||||||
|
├── 05_views.sql # Представления
|
||||||
|
└── 06_constraints.sql # (опционально) Внешние ключи
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Важные моменты
|
||||||
|
|
||||||
|
1. **Все дампы очищены** от `ROLE`, `TABLESPACE` и `OWNER`
|
||||||
|
2. **Tablespace заменен** на дефолтный
|
||||||
|
3. **OWNER заменен** на `current_user`
|
||||||
|
4. **Порядок восстановления** строго соблюден
|
||||||
|
5. **Триггеры отключены** при заливке данных
|
||||||
|
6. **Функции создаются** после таблиц и данных
|
||||||
|
7. **Триггеры создаются** после функций
|
||||||
|
8. **Представления создаются** после таблиц
|
||||||
|
|
||||||
|
Этот подход гарантирует успешную миграцию без ошибок! 🚀
|
||||||
Reference in New Issue
Block a user