家居装饰
28.14M · 2026-04-12
风险等级 操作类型 可回滚性
─────────────────────────────────────────────────
低风险 添加新表、添加新列(有默认值) 容易回滚
中风险 修改列类型、添加约束 需要计划
高风险 重命名列、删除列 困难
极高风险 删除表、清空数据 几乎不可回滚
提示词:
设计一个电商平台的数据库 Schema(PostgreSQL),
包含以下核心功能:
- 用户(支持普通用户和商家)
- 商品(多规格、多属性,如颜色+尺寸)
- 订单(支持拆单、合并)
- 购物车
- 优惠券(金额/折扣,使用限制)
- 收货地址
要求:
1. 使用 Prisma Schema 格式
2. 考虑查询性能(添加必要的索引)
3. 支持软删除
4. 考虑多租户(未来可能支持)
5. 字段命名使用 snake_case
AI 生成的 Prisma Schema 片段:
// schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
name String
role UserRole @default(CUSTOMER)
isDeleted Boolean @default(false)
deletedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
orders Order[]
addresses Address[]
cart CartItem[]
store Store? // 如果是商家,有关联店铺
@@index([email])
@@index([isDeleted, role]) // 常见查询组合
}
enum UserRole {
CUSTOMER
MERCHANT
ADMIN
}
model Product {
id String @id @default(cuid())
name String
description String?
storeId String
isDeleted Boolean @default(false)
deletedAt DateTime?
createdAt DateTime @default(now())
store Store @relation(fields: [storeId], references: [id])
variants ProductVariant[]
categories Category[]
@@index([storeId, isDeleted])
}
// 商品规格(如 颜色:红色 + 尺寸:L)
model ProductVariant {
id String @id @default(cuid())
productId String
sku String @unique
price Decimal @db.Decimal(10, 2)
stock Int @default(0)
attributes Json // {"color": "红色", "size": "L"}
product Product @relation(fields: [productId], references: [id])
orderItems OrderItem[]
cartItems CartItem[]
@@index([productId])
@@index([sku])
}
这是处理高危数据库变更的标准方法:
场景:将 users 表的 full_name 列拆分为 first_name 和 last_name
传统做法(危险):
直接修改 → 服务中断 → 数据可能丢失
扩展-收缩做法(安全):
第1步(扩展):添加新列,不删旧列
ALTER TABLE users ADD COLUMN first_name VARCHAR;
ALTER TABLE users ADD COLUMN last_name VARCHAR;
第2步(回填):异步填充新列数据
UPDATE users SET first_name = split_part(full_name, ' ', 1),
last_name = split_part(full_name, ' ', 2);
第3步(双写):应用层同时写入新旧列(部署新代码)
// 写入时:
user.full_name = `${firstName} ${lastName}`
user.first_name = firstName
user.last_name = lastName
第4步(验证):确认新列数据正确后,切换读取逻辑
第5步(收缩):删除旧列(下一个版本)
ALTER TABLE users DROP COLUMN full_name;
提示词:
我需要对生产数据库进行以下变更:
将 orders 表的 amount 字段从 FLOAT 改为 DECIMAL(10,2)
当前情况:
- 生产环境,7×24 小时运行
- orders 表约 500 万行数据
- 每秒约 50 次写入
请生成:
1. 这个变更的风险评估
2. 零停机迁移方案(分步骤)
3. 回滚方案
4. 完整的 SQL 迁移脚本
5. 迁移前后的数据验证 SQL
AI 生成的迁移方案:
-- 步骤1:添加新列(在线操作,无锁)
ALTER TABLE orders ADD COLUMN amount_decimal DECIMAL(10,2);
-- 步骤2:异步回填(分批执行,避免锁表)
DO $$
DECLARE
batch_size INT := 10000;
last_id BIGINT := 0;
max_id BIGINT;
BEGIN
SELECT MAX(id) INTO max_id FROM orders;
WHILE last_id < max_id LOOP
UPDATE orders
SET amount_decimal = ROUND(amount::DECIMAL, 2)
WHERE id > last_id AND id <= last_id + batch_size;
last_id := last_id + batch_size;
PERFORM pg_sleep(0.01); -- 避免过度占用 CPU
END LOOP;
END $$;
-- 步骤3:添加非空约束(回填完成后)
ALTER TABLE orders ALTER COLUMN amount_decimal SET NOT NULL;
-- 步骤4:验证数据一致性
SELECT COUNT(*) as mismatch_count
FROM orders
WHERE ABS(amount - amount_decimal) > 0.01;
-- 期望结果:0
-- 步骤5:在应用层切换到新字段(代码发布)
-- 步骤6:重命名字段(应用稳定后的下个版本)
ALTER TABLE orders RENAME COLUMN amount TO amount_old;
ALTER TABLE orders RENAME COLUMN amount_decimal TO amount;
-- 步骤7:确认无问题后删除旧列
ALTER TABLE orders DROP COLUMN amount_old;
-- 开启慢查询日志(PostgreSQL)
ALTER SYSTEM SET log_min_duration_statement = 1000; -- 记录超过1秒的查询
SELECT pg_reload_conf();
-- 查看最慢的查询(pg_stat_statements)
SELECT
query,
calls,
total_exec_time / calls AS avg_time_ms,
rows / calls AS avg_rows,
shared_blks_hit / calls AS cache_hits
FROM pg_stat_statements
ORDER BY avg_time_ms DESC
LIMIT 20;
把这个输出发给 AI:
以下是我们最慢的 20 个查询,请分析:
1. 哪些查询最急需优化?
2. 每个查询的问题在哪里?
3. 建议添加哪些索引?
4. 是否有可以合并的查询?
[粘贴 pg_stat_statements 输出]
# db_health_check.py
import psycopg2
from datetime import datetime
def check_database_health(connection_string: str) -> dict:
"""数据库健康检查"""
conn = psycopg2.connect(connection_string)
cur = conn.cursor()
issues = []
# 检查表膨胀
cur.execute("""
SELECT schemaname, tablename,
n_live_tup, n_dead_tup,
ROUND(n_dead_tup::NUMERIC / NULLIF(n_live_tup + n_dead_tup, 0) * 100, 2) AS bloat_pct
FROM pg_stat_user_tables
WHERE n_dead_tup > 10000
ORDER BY bloat_pct DESC
LIMIT 10
""")
bloat_tables = cur.fetchall()
for table in bloat_tables:
if table[4] and table[4] > 20:
issues.append(f"表膨胀:{table[1]} 死元组比例 {table[4]}%,建议 VACUUM ANALYZE")
# 检查缺少索引的外键
cur.execute("""
SELECT c.conrelid::regclass AS table, a.attname AS column
FROM pg_constraint c
JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = ANY(c.conkey)
WHERE c.contype = 'f'
AND NOT EXISTS (
SELECT 1 FROM pg_index i
WHERE i.indrelid = c.conrelid
AND a.attnum = ANY(i.indkey)
)
""")
missing_fk_indexes = cur.fetchall()
for fk in missing_fk_indexes:
issues.append(f"缺少外键索引:{fk[0]}.{fk[1]}")
return {
"check_time": datetime.now().isoformat(),
"issues": issues,
"is_healthy": len(issues) == 0
}
章节小结:AI 辅助数据库设计和迁移的核心价值在于:快速发现设计缺陷(N+1、缺少索引、不合理的数据类型),生成安全的迁移计划(扩展-收缩模式),以及在迁移前进行风险预警。记住:数据库是最不可原谅的失误区域,AI 的帮助让你多一双眼睛,但最终决策和验证仍需要人。