AIAI University/ Stadika Смотреть курсы
AI University / Промпты / Программисту
Программисту

Промпт: миграция базы данных без простоя

План изменения схемы по шагам expand и contract, миграции, перенос данных батчами и откат. Готовый промт на русском с ответами нейросетей: посмотрите, что выдают GigaChat, ChatGPT, Claude и Gemini, и откройте текст промпта, чтобы запускать его со своими данными.

Проверено на: GigaChatChatGPTClaudeGemini · Обновлено 01.10.2026

Текст промпта

Текст промпта открывается с доступом к библиотеке

Ответы нейросетей ниже получены этим промптом на примере из таблицы. Чтобы скопировать промпт и запускать его со своими данными, откройте доступ ко всем промптам или полный доступ к AI University.

Разовый платёж, без подписки. Новые промпты входят в доступ.

Что подставить в промт

ПолеПример
{stack}PostgreSQL 15, Alembic, приложение на FastAPI, 4 инстанса за балансировщиком
{schema}таблица users (18 млн строк): id bigint, full_name varchar(255), phone varchar(20) NULL, created_at timestamptz
{change}разделить full_name на first_name и last_name, сделать phone обязательным (сейчас 3% строк с NULL) и добавить уникальный индекс по phone
{load}пик 1 200 запросов в секунду, окна обслуживания нет, деплой по одному инстансу, есть реплика для отчётов

Ответы нейросетей на этот промпт

Один и тот же промпт с примером выше, ответы без правок: выберите нейросеть, которой пользуетесь, и посмотрите, что она выдаёт.

GigaChat 2 Max06.10.2026
Общие принципы подхода

Мы планируем изменить схему базы данных следующим образом:

Изменение схемы должно происходить плавно, чтобы минимизировать влияние на производительность системы и исключить простой приложения во время выполнения операций.

Используем подход Expand and Contract — сначала расширяем схему, вносим минимальные изменения, потом постепенно добавляем бизнес-логику и финализируем структуру.


Пошаговый план изменений (Expand & Contract)
Шаг 1: Expand — расширение структуры

Создаём новые столбцы и начинаем заполнять существующий набор данных небольшими партиями.

Миграция №1: создание новых полей и индексация телефона (по частям):
def upgrade():
    op.add_column('users', sa.Column('first_name', sa.String(length=255)))
    op.add_column('users', sa.Column('last_name', sa.String(length=255)))

    # Создаем index_concurrently для уникального индекса, который будет выполняться параллельно и асинхронно,
    # что позволяет избежать длительных блокировок.
    conn = op.get_bind()
    conn.execute(sa.text("CREATE UNIQUE INDEX CONCURRENTLY idx_users_phone_unique ON users(phone);"))

def downgrade():
    with op.batch_alter_table('users') as batch_op:
        batch_op.drop_index('idx_users_phone_unique')
        batch_op.drop_column('first_name')
        batch_op.drop_column('last_name')

После успешной миграции делаем следующий шаг.

Шаг 2: Заполнение новыми значениями batched-запросами (скрипт Python).

Заполняем таблицу маленькими порциями, чтобы не создавать большие транзакции и тяжелые блокировки.

import psycopg2
from time import sleep

# Параметры подключения
DB_HOST = 'your_db_host'
DB_NAME = 'your_db_name'
DB_USER = 'your_user'
DB_PASSWORD = 'your_password'
BATCH_SIZE = 10_000
PAUSE_SECONDS = 10

conn = psycopg2.connect(
    host=DB_HOST,
    database=DB_NAME,
    user=DB_USER,
    password=DB_PASSWORD
)
cur = conn.cursor()

query_template = """
UPDATE users 
SET first_name = split_part(full_name, ' ', 1),
    last_name = CASE WHEN strpos(full_name, ' ') > 0 THEN substring(full_name from position(' ' in full_name)+1 for char_length(full_name)) ELSE '' END
WHERE id BETWEEN %s AND %s;
"""

min_id = cur.fetchone()[0]
max_id = cur.fetchone()[0]

for start_id in range(min_id, max_id + BATCH_SIZE, BATCH_SIZE):
    end_id = min(start_id + BATCH_SIZE - 1, max_id)
    print(f'Processing IDs {start_id}-{end_id}')
    cur.execute(query_template, (start_id, end_id))
    conn.commit()
    sleep(PAUSE_SECONDS)

print('Migration completed.')
cur.close()
conn.close()

Размер партии в 10 тыс. записей достаточно мал, чтобы обновление прошло быстро и эффективно. Пауза между пакетами поможет разгрузить систему, особенно при высокой нагрузке.

Проверяем успешность миграции данных перед переходом к следующему этапу.

Шаг 3: Добавляем обязательность для поля phone

Создаем новую миграцию, где сделаем поле телефон обязательным (не допускающим пустых значений). Поскольку изначально в таблице около 3% null-значений, заполняем их заранее случайным временным значением до полной замены данных.

Миграция №2: заполнить пустые телефоны временными значениями и сделать обязательное поле:
def upgrade():
    # Временно заменяем NULL-телефоны на временное значение ("N/A"), которое позже удалится
    conn = op.get_bind()
    conn.execute(sa.text("UPDATE users SET phone='N/A' WHERE phone IS NULL;"))
    
    # Устанавливаем NOT NULL ограничение
    with op.batch_alter_table('users') as batch_op:
        batch_op.alter_column('phone', nullable=False)

def downgrade():
    with op.batch_alter_table('users') as batch_op:
        batch_op.alter_column('phone', nullable=True)
    conn = op.get_bind()
    conn.execute(sa.text("UPDATE users SET phone=NULL WHERE phone='N/A';"))

Переносите эту миграцию отдельно и убедитесь, что временные значения правильно установлены.

Шаг 4: Code Change — модификация бизнес-логики

Теперь вы можете вносить изменения в код вашего API, используя обновленные поля и новое требование обязательного заполнения номера телефона.

После завершения изменений в коде перезапускайте серверы последовательно один за другим, чтобы уменьшить влияние изменений на пользователей.

Шаг 5: Удаление старых колонок и индексов

Финальная миграция уберёт старые колонки и завершит процесс перехода.

Миграция №3: удаление старого поля full_name.
def upgrade():
    with op.batch_alter_table('users') as batch_op:
        batch_op.drop_column('full_name')

def downgrade():
    op.add_column('users', sa.Column('full_name', sa.String(length=255)))

На данном этапе также рекомендуется удалить временной индекс, созданный ранее (если применялся индекс CONCURRENTLY):

DROP INDEX IF EXISTS idx_users_phone_unique;

Затем создаем новый постоянный уникальный индекс по телефону:

CREATE UNIQUE INDEX idx_users_phone_unique ON users(phone);

Эта операция выполняется через команду CREATE UNIQUE INDEX CONCURRENTLY, чтобы избегать длительных блокировок.


Тяжёлые блокировки и как их избежать

В PostgreSQL существуют несколько типов операций, вызывающих долгие блокировки:

Для минимизации влияния эти операции выполняются поэтапно и с использованием следующих методов:

Эти подходы позволяют снизить нагрузку на базу данных и избежать продолжительного снижения производительности или отказа работы приложения.

Проверки после каждой миграции

Перед каждым этапом важно убедиться, что система продолжает стабильно функционировать:

Откат на каждом шаге

При возникновении проблем на любом этапе вам потребуется возможность быстрого отката назад.

Каждый шаг требует подготовки обратимых миграций и скриптов отката, которые будут возвращать систему в исходное состояние.

Заключение

Следуя такому плану, вы сможете провести необходимые изменения без длительного простоя сервиса и значительных влияний на производительность системы даже при высоких нагрузках. Важно проводить каждое действие аккуратно, внимательно проверяя промежуточные результаты и стабильность работы сервиса.

Советы

Как пользоваться
  1. Откройте доступ и скопируйте промпт кнопкой выше.
  2. Замените поля в фигурных скобках своими данными.
  3. Отправьте в нейросеть и сравните ответ с примером на этой странице.

Подробнее о структуре хорошего запроса: гид AI University.

Похожие промпты

ПрограммистуБесплатно Найти причину ошибки по стектрейсу и логамВероятная причина плавающей ошибки, гипотезы с проверками, исправление и защита от повторения. 4 ответаОткрытьПрограммистуБесплатно Ускорить медленный SQL-запрос по EXPLAINРазбор плана выполнения, индексы и переписанный запрос, безопасное создание индекса на проде. 4 ответаОткрытьПрограммистуБесплатно Ревью pull request по diffРевью изменений с приоритетами: блокирующие ошибки, безопасность, тесты, готовые комментарии. 4 ответаОткрыть

Все 435 промптов и 6 наборов

172 промптов открыты бесплатно. Остальные и наборы-цепочки открывает доступ к библиотеке за 1 490 ₽. Полный доступ за 4 900 ₽: все курсы AI University на русском и библиотека промптов. Разовый платёж, новые промпты входят.