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