405 lines
9.5 KiB
Markdown
405 lines
9.5 KiB
Markdown
# Example Complete Workflow
|
||
|
||
Un esempio passo-passo di come usare il tool per una migrazione completa.
|
||
|
||
## Scenario
|
||
|
||
Devi migrare il database MySQL `production_db` a PostgreSQL, incluso setup del container Incus e test di performance.
|
||
|
||
### Dati
|
||
- RAWDATACOR: ~50 milioni di righe (5 anni di dati)
|
||
- ELABDATADISP: ~25 milioni di righe
|
||
|
||
### Timeline
|
||
- Tempo disponibile: 2 ore per migrazione
|
||
- Test: 30 minuti
|
||
- Validazione: 30 minuti
|
||
|
||
## Step-by-Step Workflow
|
||
|
||
### 1. Preparazione (10 min)
|
||
|
||
```bash
|
||
# Clonare il progetto
|
||
cd /home/user/projects
|
||
git clone <repo> mysql2postgres
|
||
cd mysql2postgres
|
||
|
||
# Setup Python
|
||
./install.sh
|
||
source venv/bin/activate
|
||
|
||
# Verificare Python
|
||
python --version
|
||
# Output: Python 3.10.x
|
||
```
|
||
|
||
### 2. Setup Container PostgreSQL (10 min)
|
||
|
||
```bash
|
||
# Creare e configurare container Incus
|
||
bash scripts/incus_setup.sh pg-prod password123
|
||
|
||
# Output:
|
||
# ✓ PostgreSQL is running!
|
||
#
|
||
# Connection details:
|
||
# Host: 10.100.50.123
|
||
# Port: 5432
|
||
# User: postgres
|
||
# Password: password123
|
||
#
|
||
# Update .env file with:
|
||
# POSTGRES_HOST=10.100.50.123
|
||
# POSTGRES_PASSWORD=password123
|
||
```
|
||
|
||
### 3. Configurazione (5 min)
|
||
|
||
```bash
|
||
# Copiare template e editare
|
||
cp .env.example .env
|
||
nano .env
|
||
|
||
# Configurazione finale:
|
||
# MYSQL_HOST=db.production.com
|
||
# MYSQL_PORT=3306
|
||
# MYSQL_USER=migration_user
|
||
# MYSQL_PASSWORD=secure_password
|
||
# MYSQL_DATABASE=production_db
|
||
#
|
||
# POSTGRES_HOST=10.100.50.123
|
||
# POSTGRES_PORT=5432
|
||
# POSTGRES_USER=postgres
|
||
# POSTGRES_PASSWORD=password123
|
||
# POSTGRES_DATABASE=production_migrated
|
||
#
|
||
# LOG_LEVEL=INFO
|
||
# CONSOLIDATION_GROUP_LIMIT=80000 # Large batches for speed
|
||
# PROGRESS_LOG_INTERVAL=20000
|
||
```
|
||
|
||
### 4. Verifica Configurazione (5 min)
|
||
|
||
```bash
|
||
python main.py info
|
||
|
||
# Output:
|
||
# [MySQL Configuration]
|
||
# Host: db.production.com:3306
|
||
# Database: production_db
|
||
# User: migration_user
|
||
#
|
||
# [PostgreSQL Configuration]
|
||
# Host: 10.100.50.123:5432
|
||
# Database: production_migrated
|
||
# User: postgres
|
||
#
|
||
# [Migration Settings]
|
||
# Batch Size: 50000
|
||
# Log Level: INFO
|
||
# Dry Run: False
|
||
```
|
||
|
||
### 5. Setup Schema PostgreSQL (5 min)
|
||
|
||
```bash
|
||
# Creare schema con partizioni e indici
|
||
python main.py setup --create-schema
|
||
|
||
# Output:
|
||
# Connected to PostgreSQL: 10.100.50.123:5432/production_migrated
|
||
# Creating PostgreSQL schema...
|
||
# ✓ Schema creation complete
|
||
# ✓ PostgreSQL schema created successfully
|
||
```
|
||
|
||
### 6. Verifica Connessione MySQL (2 min)
|
||
|
||
```bash
|
||
# Fare una query test MySQL
|
||
python -c "
|
||
from src.connectors.mysql_connector import MySQLConnector
|
||
with MySQLConnector() as conn:
|
||
count = conn.get_row_count('RAWDATACOR')
|
||
print(f'RAWDATACOR: {count:,} rows')
|
||
count = conn.get_row_count('ELABDATADISP')
|
||
print(f'ELABDATADISP: {count:,} rows')
|
||
"
|
||
|
||
# Output:
|
||
# RAWDATACOR: 50,234,567 rows
|
||
# ELABDATADISP: 25,789,123 rows
|
||
```
|
||
|
||
### 7. Dry-Run Migration (Opzionale, 10 min)
|
||
|
||
```bash
|
||
# Testare senza modificare i dati
|
||
python main.py migrate full --dry-run
|
||
|
||
# Output:
|
||
# [DRY RUN] Would migrate all rows
|
||
# ✓ Migration complete: 50234567 rows migrated to rawdatacor
|
||
# ✓ RAWDATACOR: 50234567 rows migrated
|
||
# [DRY RUN] Would migrate all rows
|
||
# ✓ Migration complete: 25789123 rows migrated to elabdatadisp
|
||
# ✓ ELABDATADISP: 25789123 rows migrated
|
||
# ✓ Full migration complete: 76023690 total rows migrated
|
||
```
|
||
|
||
### 8. Migrazione Completa (60 min per dati grandi)
|
||
|
||
```bash
|
||
# Lanciare la migrazione vera
|
||
python main.py migrate full
|
||
|
||
# Output:
|
||
# Migrating RAWDATACOR...
|
||
# Migrating RAWDATACOR ██████████████░░░░░░░░░░░░░░░░░░░░░░░░ 35% 00:42:15
|
||
# ✓ RAWDATACOR: 50234567 rows migrated
|
||
#
|
||
# Migrating ELABDATADISP...
|
||
# Migrating ELABDATADISP ████████████████████████████████░░░░░░░░░░ 75% 00:15:30
|
||
# ✓ ELABDATADISP: 25789123 rows migrated
|
||
#
|
||
# ✓ Full migration complete: 76023690 total rows migrated
|
||
|
||
# ⏱ Timing per RAWDATACOR:
|
||
# - 50M rows
|
||
# - 50k batch size = 1000 transazioni
|
||
# - ~3 sec per batch
|
||
# - Total: ~50 minuti
|
||
```
|
||
|
||
### 9. Validazione Dati (15 min)
|
||
|
||
```bash
|
||
# Connettere a PostgreSQL e validare
|
||
psql -h 10.100.50.123 -U postgres -d production_migrated
|
||
|
||
# SQL validation queries
|
||
postgres=# SELECT COUNT(*) FROM rawdatacor;
|
||
# count: 50234567
|
||
|
||
postgres=# SELECT COUNT(*) FROM elabdatadisp;
|
||
# count: 25789123
|
||
|
||
postgres=# SELECT event_date, COUNT(*) FROM rawdatacor GROUP BY event_date ORDER BY event_date LIMIT 10;
|
||
# Verificare distribuzione date
|
||
|
||
postgres=# SELECT measurements FROM rawdatacor WHERE measurements IS NOT NULL LIMIT 1 \gx
|
||
# Verificare struttura JSONB
|
||
|
||
# Esecuzione script validazione
|
||
\i scripts/validate_migration.sql
|
||
|
||
# Controllare:
|
||
# - Row counts match
|
||
# - No NULL measurements
|
||
# - Date ranges correct
|
||
# - Indexes created
|
||
# - Partitions exist
|
||
```
|
||
|
||
### 10. Benchmark Performance (30 min)
|
||
|
||
```bash
|
||
# Eseguire benchmark con 10 iterazioni
|
||
python main.py benchmark --iterations 10 --output production_benchmark.json
|
||
|
||
# Output example:
|
||
# Running performance benchmarks...
|
||
#
|
||
# [RAWDATACOR]
|
||
# select_by_pk:
|
||
# MySQL: 0.45ms (min: 0.35ms, max: 0.65ms)
|
||
# PostgreSQL: 0.32ms (min: 0.28ms, max: 0.38ms)
|
||
# ✓ PostgreSQL is 1.4x faster
|
||
#
|
||
# select_by_date_range:
|
||
# MySQL: 125.50ms (min: 120.00ms, max: 135.00ms)
|
||
# PostgreSQL: 45.20ms (min: 42.00ms, max: 50.00ms)
|
||
# ✓ PostgreSQL is 2.8x faster
|
||
#
|
||
# jsonb_filter_value:
|
||
# PostgreSQL: 32.10ms (min: 28.00ms, max: 38.00ms)
|
||
# (MySQL non supporta JSONB)
|
||
#
|
||
# [ELABDATADISP]
|
||
# ...
|
||
#
|
||
# ✓ Benchmark complete: results saved to benchmark_results/benchmark_20240115_143022.json
|
||
```
|
||
|
||
### 11. Analizzare Risultati Benchmark
|
||
|
||
```bash
|
||
# Visualizzare JSON results
|
||
cat production_benchmark.json | python -m json.tool
|
||
|
||
# Risultati attesi:
|
||
# - SELECT semplici: PostgreSQL 2-3x più veloce
|
||
# - Range query: PostgreSQL 2-4x più veloce
|
||
# - JSONB query: Solo PostgreSQL (non disponibili in MySQL)
|
||
# - Aggregazioni: PostgreSQL simile o migliore
|
||
|
||
# Interpretazione:
|
||
# - RAWDATACOR con JSONB: beneficio 30-50% (meno colonne in storage)
|
||
# - ELABDATADISP con JSONB: beneficio 20-30% (compressione dei NULL)
|
||
```
|
||
|
||
### 12. Setup Migrazioni Incrementali (5 min)
|
||
|
||
```bash
|
||
# Configurare cron per sincronizzazione periodica
|
||
bash scripts/setup_cron.sh
|
||
|
||
# Quando viene chiesto se aggiungere il cron:
|
||
# Aggiunge:
|
||
# 0 */6 * * * cd /path/to/mysql2postgres && python main.py migrate incremental >> migration_*.log 2>&1
|
||
#
|
||
# Risultato: esecuzione ogni 6 ore
|
||
|
||
# Verificare
|
||
crontab -l | grep migrate
|
||
# Output: 0 */6 * * * cd /home/user/projects/mysql2postgres && ...
|
||
```
|
||
|
||
### 13. Primo Test Migrazioni Incrementali (5 min)
|
||
|
||
```bash
|
||
# Simulare cambiamenti in MySQL
|
||
# (aggiungere alcuni record nuovi)
|
||
|
||
# Poi eseguire migrazione incrementale
|
||
python main.py migrate incremental
|
||
|
||
# Output:
|
||
# Incremental migration for RAWDATACOR...
|
||
# ℹ RAWDATACOR: 0 rows migrated
|
||
#
|
||
# Incremental migration for ELABDATADISP...
|
||
# ℹ ELABDATADISP: 0 rows migrated
|
||
#
|
||
# ℹ No rows to migrate
|
||
|
||
# Oppure se ci sono dati:
|
||
# Incremental migration for RAWDATACOR...
|
||
# ✓ RAWDATACOR: 1234 rows migrated
|
||
#
|
||
# ✓ Incremental migration complete: 1234 total rows migrated
|
||
```
|
||
|
||
## Risultati Attesi
|
||
|
||
### Tempo Totale
|
||
- Setup: 30 minuti
|
||
- Migrazione: 60-90 minuti (dipende da dimensione)
|
||
- Test: 30 minuti
|
||
- **Totale: 2-3 ore**
|
||
|
||
### Performance Gains
|
||
- Storage: 10-20% riduzione (JSONB compressione)
|
||
- Query tempo: 2-4x più veloce su PostgreSQL
|
||
- Indici: più efficienti con JSONB GIN
|
||
|
||
### Validazione
|
||
- Row counts: Match 100%
|
||
- Date ranges: Completi
|
||
- JSONB structure: Valida
|
||
- Indexes: Tutti creati
|
||
- Partitions: Funzionanti
|
||
|
||
## Troubleshooting Durante Workflow
|
||
|
||
### Errore: "Cannot connect to MySQL"
|
||
```bash
|
||
# Verificare credenziali
|
||
mysql -h db.production.com -u migration_user -p -e "SELECT 1" < /dev/null
|
||
|
||
# Verificare firewall
|
||
nc -zv db.production.com 3306
|
||
|
||
# Controllare .env
|
||
grep MYSQL .env
|
||
```
|
||
|
||
### Errore: "Schema creation failed"
|
||
```bash
|
||
# Verificare PostgreSQL online
|
||
psql -h 10.100.50.123 -U postgres -c "SELECT version()"
|
||
|
||
# Recreate schema
|
||
python main.py setup --create-schema
|
||
```
|
||
|
||
### Migrazione molto lenta
|
||
```bash
|
||
# Aumentare consolidation group limit temporaneamente
|
||
# Editare .env: CONSOLIDATION_GROUP_LIMIT=100000
|
||
|
||
# Ridurre logging
|
||
# Editare .env: PROGRESS_LOG_INTERVAL=50000
|
||
|
||
# Oppure verificare:
|
||
# - Latency rete MySQL↔PostgreSQL
|
||
# - CPU/Memoria su entrambi i server
|
||
# - Disk I/O disponibile
|
||
```
|
||
|
||
## Monitoraggio Durante Migrazione
|
||
|
||
```bash
|
||
# In un altro terminale, monitorare progresso
|
||
watch "ps aux | grep -i 'python main.py'"
|
||
|
||
# Oppure monitorare database
|
||
# PostgreSQL
|
||
psql -h 10.100.50.123 -U postgres -d production_migrated \
|
||
-c "SELECT COUNT(*) FROM rawdatacor"
|
||
|
||
# MySQL
|
||
mysql -h db.production.com -u migration_user -p production_db \
|
||
-e "SELECT COUNT(*) FROM RAWDATACOR"
|
||
```
|
||
|
||
## Post-Migration Checklist
|
||
|
||
- [ ] Row counts match MySQL e PostgreSQL
|
||
- [ ] Date ranges sono completi
|
||
- [ ] JSONB structure è valido
|
||
- [ ] Indici sono stati creati
|
||
- [ ] Query critiche funzionano su PostgreSQL
|
||
- [ ] Benchmark mostra improvement
|
||
- [ ] Cron job per incremental è configurato
|
||
- [ ] Backups dei dati migration sono salvati
|
||
- [ ] Log di migrazione sono archiviati
|
||
|
||
## Documenti da Archiviare
|
||
|
||
```bash
|
||
# Creare directory backup
|
||
mkdir -p backups/migration_$(date +%Y%m%d)
|
||
|
||
# Salvare:
|
||
# - benchmark results
|
||
# - migration logs
|
||
# - .env file (con password rimossa)
|
||
# - validation output
|
||
# - timing reports
|
||
|
||
cp production_benchmark.json backups/migration_*/
|
||
cp *.log backups/migration_*/ 2>/dev/null || true
|
||
```
|
||
|
||
## Successo!
|
||
|
||
Quando tutto è completato:
|
||
|
||
✓ Dati migrati completamente
|
||
✓ Performance validata (PostgreSQL più veloce)
|
||
✓ JSONB schema funzionante
|
||
✓ Migrazioni incrementali configurate
|
||
✓ Pronto per switchover produzione
|