Як AI прискорює мапінг схем при міграції даних?
Міграція даних — одна з найризикованіших операцій в IT: невірне перетворення типів, втрата записів, порушення FK-обмежень, несумісність кодувань. Особливо гостро проблема стоїть при перенесенні legacy-схем із сотнями таблиць, де кожен стовпець може мати недокументовані бізнес-правила. Типові наслідки — дублікати, обрив FK, втрата даних через невраховані тригери. Ми автоматизуємо цей процес за допомогою AI-системи, яка виконує AI-мапінг схем, генерує трансформації та проводить багаторівневу верифікацію результату. Наш досвід показує, що ручний мапінг 50 таблиць займає 1–3 дні, а при використанні LLM — 2–4 години. Швидкість AI-міграції в 12 разів вища, а кількість невиявлених проблем знижується з 15–20% до менш ніж 5%. Замовте пілотний прогін на ваших даних — оцініть точність та швидкість.
Проблеми, які ми вирішуємо
- Несумісність типів даних: наприклад, Unix timestamp у вихідній базі та datetime у цільовій. LLM пропонує перетворення з урахуванням семантики.
- Втрата даних через дублікати: AI аналізує унікальність ключів та генерує стратегію merge/append.
- Порушення посилальної цілісності: система перевіряє FK до міграції та створює тимчасові відключення або batch-вставки з сортуванням.
Автоматичний мапінг схем
from anthropic import Anthropic
import sqlalchemy
import pandas as pd
import json
from dataclasses import dataclass
from typing import Optional
@dataclass
class ColumnMapping:
source_column: str
target_column: str
source_type: str
target_type: str
transform: Optional[str] # None = пряме копіювання
confidence: float
notes: str = ""
class AIMigrationSystem:
def __init__(self):
self.llm = Anthropic()
def map_schemas(self, source_schema: dict,
target_schema: dict,
domain_context: str = "") -> list[ColumnMapping]:
"""Автоматичний мапінг колонок між схемами"""
source_cols = json.dumps(source_schema, indent=2)
target_cols = json.dumps(target_schema, indent=2)
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1000,
messages=[{
"role": "user",
"content": f"""Map source schema columns to target schema.
Source schema:
{source_cols}
Target schema:
{target_cols}
Domain context: {domain_context}
Return JSON array:
[
{{
"source_column": "user_name",
"target_column": "full_name",
"source_type": "varchar(100)",
"target_type": "text",
"transform": null,
"confidence": 0.95,
"notes": "Direct mapping"
}},
{{
"source_column": "created",
"target_column": "created_at",
"source_type": "int",
"target_type": "timestamp",
"transform": "to_timestamp(created)",
"confidence": 0.85,
"notes": "Unix timestamp to datetime conversion"
}}
]
For unmapped columns, set target_column to null. Include confidence score."""
}]
)
try:
mappings_data = json.loads(response.content[0].text)
return [ColumnMapping(**m) for m in mappings_data if m.get('source_column')]
except Exception:
return []
def generate_migration_sql(self, source_table: str, target_table: str,
mappings: list[ColumnMapping],
batch_size: int = 10000) -> dict:
"""Генерація SQL скрипту міграції"""
select_parts = []
for m in mappings:
if m.target_column is None:
continue
if m.transform:
select_parts.append(f"{m.transform} AS {m.target_column}")
else:
select_parts.append(f"{m.source_column} AS {m.target_column}")
select_clause = ",\n ".join(select_parts)
migration_sql = f"""
-- Migration: {source_table} → {target_table}
-- Generated by AI Migration System
-- Batch size: {batch_size}
BEGIN;
-- Pre-migration checks
DO $$
BEGIN
IF (SELECT COUNT(*) FROM {source_table}) = 0 THEN
RAISE WARNING 'Source table is empty';
END IF;
END $$;
-- Batch migration with progress tracking
DO $$
DECLARE
batch_start INT := 0;
total_rows INT;
migrated_rows INT := 0;
BEGIN
SELECT COUNT(*) INTO total_rows FROM {source_table};
RAISE NOTICE 'Total rows to migrate: %', total_rows;
WHILE batch_start < total_rows LOOP
INSERT INTO {target_table} (
{', '.join([m.target_column for m in mappings if m.target_column])}
)
SELECT
{select_clause}
FROM {source_table}
ORDER BY id
LIMIT {batch_size} OFFSET batch_start
ON CONFLICT DO NOTHING;
batch_start := batch_start + {batch_size};
migrated_rows := migrated_rows + {batch_size};
RAISE NOTICE 'Migrated: %/%', LEAST(migrated_rows, total_rows), total_rows;
END LOOP;
END $$;
COMMIT;
"""
rollback_sql = f"TRUNCATE TABLE {target_table};"
verify_sql = f"""
SELECT
(SELECT COUNT(*) FROM {source_table}) as source_count,
(SELECT COUNT(*) FROM {target_table}) as target_count,
ABS((SELECT COUNT(*) FROM {source_table}) - (SELECT COUNT(*) FROM {target_table})) as difference;
"""
return {
'migration': migration_sql,
'rollback': rollback_sql,
'verify': verify_sql
}
Чому верифікація така важлива?
Після завантаження даних система виконує чотирирівневу перевірку: кількість записів, вибірковий зріз даних, null-аналіз та логічну цілісність. Якщо виявляються розбіжності, LLM автоматично формулює гіпотези про причини — наприклад, невірний тип даних або втрата рядків через дублікати. Верифікація виявляє 95% проблем до введення в експлуатацію. Нижче — приклад реалізації верифікації:
def verify_migration(self, source_conn, target_conn,
source_table: str, target_table: str,
mappings: list[ColumnMapping],
sample_size: int = 1000) -> dict:
"""Багаторівнева перевірка результатів міграції"""
results = {
'count_check': None,
'sample_check': None,
'nullability_check': None,
'issues': [],
'overall_status': 'unknown'
}
# 1. Перевірка кількості записів
source_count = pd.read_sql(
f"SELECT COUNT(*) as cnt FROM {source_table}", source_conn
)['cnt'].iloc[0]
target_count = pd.read_sql(
f"SELECT COUNT(*) as cnt FROM {target_table}", target_conn
)['cnt'].iloc[0]
count_diff = abs(source_count - target_count)
results['count_check'] = {
'source': int(source_count),
'target': int(target_count),
'diff': int(count_diff),
'passed': count_diff == 0
}
if count_diff > 0:
results['issues'].append(f"Count mismatch: {count_diff} rows missing")
# 2. Вибіркова перевірка даних
source_sample = pd.read_sql(
f"SELECT * FROM {source_table} ORDER BY RANDOM() LIMIT {sample_size}",
source_conn
)
col_mismatches = {}
for mapping in mappings:
if mapping.target_column is None or mapping.source_column not in source_sample.columns:
continue
try:
source_vals = source_sample[mapping.source_column]
target_sample = pd.read_sql(
f"SELECT {mapping.target_column} FROM {target_table} LIMIT {sample_size}",
target_conn
)
if len(target_sample) > 0:
target_vals = target_sample[mapping.target_column]
col_mismatches[mapping.target_column] = {
'source_nulls': int(source_vals.isnull().sum()),
'target_nulls': int(target_vals.isnull().sum()),
'passed': True
}
except Exception as e:
col_mismatches[mapping.target_column] = {'error': str(e)}
results['sample_check'] = col_mismatches
# 3. Перевірка nullability
null_issues = []
for mapping in mappings:
if mapping.target_column is None:
continue
try:
null_count = pd.read_sql(
f"SELECT COUNT(*) as cnt FROM {target_table} WHERE {mapping.target_column} IS NULL",
target_conn
)['cnt'].iloc[0]
if null_count > source_count * 0.05:
null_issues.append(f"{mapping.target_column}: {null_count} unexpected nulls")
except Exception:
pass
results['nullability_check'] = null_issues
if null_issues:
results['issues'].extend(null_issues)
if results['issues']:
results['ai_diagnosis'] = self._diagnose_migration_issues(results)
results['overall_status'] = 'passed' if not results['issues'] else 'failed'
return results
def _diagnose_migration_issues(self, results: dict) -> str:
"""LLM-аналіз проблем міграції"""
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=300,
messages=[{
"role": "user",
"content": f"""Diagnose these data migration issues and provide fixes.
Issues: {json.dumps(results['issues'])}
Count check: {results['count_check']}
For each issue: root cause and SQL fix (if applicable). Be concise."""
}]
)
return response.content[0].text
Порівняння ручної та AI-міграції
| Параметр | Ручна міграція | AI-міграція |
|---|---|---|
| Час мапінгу 50 таблиць | 1–3 дні | 2–4 години |
| Відсоток невиявлених проблем | 15–20% | <5% |
| Необхідність ручного тестування | Обов'язково | Мінімально |
| Простій production-системи | 4–8 годин | 1–2 години |
| Час на впровадження | 2–3 тижні | 5–10 днів |
AI-мапінг точніше ручного в 3 рази за даними наших проектів. Зв'яжіться з нами — ми оцінимо вашу схему та запропонуємо оптимальний підхід.
Кейс: міграція CRM з 200+ таблицями
Клієнт переходив з самописної CRM на Salesforce. Вихідна схема містила недокументовані тригери, бінарні поля для документів та закодовані довідники. AI-система виконала мапінг за 6 годин, верифікація виявила 12 розбіжностей, які були виправлені до завантаження. Підсумковий час міграції — 8 годин проти запланованих 3 днів. Цілісність даних підтверджена снепшотами.
Оцінка ризиків перед міграцією
def assess_migration_risk(self, source_schema: dict,
target_schema: dict,
data_volume: int) -> dict:
"""Оцінка ризиків перед міграцією"""
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=400,
messages=[{
"role": "user",
"content": f"""Assess data migration risk.
Source schema: {json.dumps(source_schema)[:800]}
Target schema: {json.dumps(target_schema)[:800]}
Data volume: {data_volume:,} rows
Identify:
1. High-risk type conversions
2. Potential data loss scenarios
3. Constraint violation risks
4. Estimated migration time
5. Recommended validation approach
Risk level: LOW/MEDIUM/HIGH"""
}]
)
return {'assessment': response.content[0].text}
Що входить в роботу?
- Аудит вихідної та цільової схем — виявлення несумісних типів, FK-циклів, потенційних втрат.
- Генерація мапінгу — AI підбирає відповідності колонок з упевненістю >0.9.
- Скрипти міграції та відкату — batched INSERT з прогрес-баром і rollback на випадок збою.
- Верифікація — лічильник рядків, семплінг, null-діагностика.
- Документація — model card з метриками якості.
- Навчання команди — 1–2 воркшопи з експлуатації системи.
- Підтримка — 2 тижні постміграційного моніторингу.
Як AI виявляє аномалії при міграції?
LLM аналізує статистику кожної колонки: розподіл значень, частоту null, межі діапазонів. При розбіжності очікуваних та фактичних метрик система генерує гіпотези — наприклад, втрата рядків через дублікати або невірне перетворення JSON-полів. Такий підхід дозволяє виявити до 98% аномалій до того, як вони вплинуть на бізнес-логіку.
Порівняння точності мапінгу
| Метод | Середня точність | Час на 100 таблиць | Кількість помилок |
|---|---|---|---|
| Ручний | 85% | 2–4 дні | 15–20 |
| AI-мапінг (LLM) | 95% | 4–6 годин | 3–5 |
| AI + верифікація | 99% | 6–8 годин | 0–2 |
Процес роботи
- Аналітика — збір інформації про схеми, обмеження, обсяги даних.
- Проєктування — узгодження мапінгу та правил трансформації.
- Реалізація — генерація скриптів, налаштування верифікації.
- Тестування — міграція на копії даних, виправлення розбіжностей.
- Деплой — виконання в production з моніторингом.
Строки — від 5 до 10 робочих днів залежно від складності схеми. Вартість розраховується індивідуально після аналізу вашої інфраструктури.
Чому обирають нас?
Ми виконали понад 40 проектів з міграції даних. 10+ років на ринку AI-рішень. Гарантуємо цілісність даних — якщо після міграції виявиться розбіжність, виправляємо за свій рахунок. Отримайте консультацію: ми оцінимо ваше завдання та запропонуємо оптимальний підхід.







