数据库辅助
wescode 的数据库辅助功能帮助你完成 SQL 编写、Schema 设计、数据迁移、查询优化和 ORM 代码生成。
功能概览
| 能力 | 说明 |
|---|---|
| SQL 生成 | 用自然语言描述需求,自动生成 SQL |
| Schema 设计 | 辅助设计合理的数据库表结构 |
| 数据迁移 | 生成安全的迁移脚本 |
| 查询优化 | 分析慢查询,建议优化方案 |
| ORM 辅助 | 生成 ORM 模型和查询代码 |
SQL 生成
自然语言转 SQL
用中文或英文描述需求,AI 自动生成对应的 SQL:
用户:查询最近 30 天内下单金额超过 1000 的用户,按总金额排序
AI:
SELECT
u.id,
u.username,
u.email,
SUM(o.total_amount) AS total_spent,
COUNT(o.id) AS order_count
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.created_at >= NOW() - INTERVAL '30 days'
AND o.status = 'completed'
GROUP BY u.id, u.username, u.email
HAVING SUM(o.total_amount) > 1000
ORDER BY total_spent DESC;
说明:
- 只计算已完成的订单(status = 'completed')
- 使用 SUM 聚合计算总金额
- HAVING 在 GROUP BY 之后过滤
支持的数据库方言
| 数据库 | 方言特性 |
|---|---|
| PostgreSQL | 窗口函数、CTE、JSONB、数组类型 |
| MySQL | INDEX HINT、特有函数、编码设置 |
| SQLite | 简化语法、类型亲和性 |
| SQL Server | TOP、OFFSET-FETCH、T-SQL |
AI 会根据项目的数据库类型自动选择正确的方言:
用户:分页查询用户列表
AI(PostgreSQL):
SELECT * FROM users
ORDER BY created_at DESC
LIMIT $1 OFFSET $2;
AI(MySQL):
SELECT * FROM users
ORDER BY created_at DESC
LIMIT ?, ?;
复杂查询生成
用户:统计每个部门的平均工资、最高工资、人数,
排除实习生,只显示人数超过 5 的部门
AI:
WITH dept_stats AS (
SELECT
d.name AS department,
AVG(e.salary) AS avg_salary,
MAX(e.salary) AS max_salary,
COUNT(*) AS headcount
FROM employees e
JOIN departments d ON e.department_id = d.id
WHERE e.employment_type != 'intern'
GROUP BY d.id, d.name
HAVING COUNT(*) > 5
)
SELECT
department,
ROUND(avg_salary, 2) AS avg_salary,
max_salary,
headcount
FROM dept_stats
ORDER BY avg_salary DESC;
Schema 设计
从需求设计表结构
用户:设计一个电商系统的订单模块数据库
AI:订单模块 Schema 设计:
-- 订单主表
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
order_no VARCHAR(32) NOT NULL UNIQUE,
user_id BIGINT NOT NULL REFERENCES users(id),
status VARCHAR(20) NOT NULL DEFAULT 'pending',
total_amount DECIMAL(12, 2) NOT NULL,
currency VARCHAR(3) NOT NULL DEFAULT 'CNY',
remark TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
paid_at TIMESTAMPTZ,
shipped_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ
);
-- 订单商品表
CREATE TABLE order_items (
id BIGSERIAL PRIMARY KEY,
order_id BIGINT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
product_id BIGINT NOT NULL REFERENCES products(id),
sku_id BIGINT REFERENCES product_skus(id),
quantity INT NOT NULL CHECK (quantity > 0),
unit_price DECIMAL(12, 2) NOT NULL,
subtotal DECIMAL(12, 2) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 订单状态流转记录
CREATE TABLE order_status_logs (
id BIGSERIAL PRIMARY KEY,
order_id BIGINT NOT NULL REFERENCES orders(id),
from_status VARCHAR(20),
to_status VARCHAR(20) NOT NULL,
operator VARCHAR(64),
reason TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 索引
CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_orders_status ON orders(status);
CREATE INDEX idx_orders_created_at ON orders(created_at);
CREATE INDEX idx_order_items_order_id ON order_items(order_id);
CREATE INDEX idx_order_items_product_id ON order_items(product_id);
设计要点:
1. 金额使用 DECIMAL(12,2),避免浮点精度问题
2. 时间字段使用 TIMESTAMPTZ,支持时区
3. 订单号独立于自增 ID,业务可读
4. 状态流转有日志表,便于审计
5. 外键约束保证数据一致性
Schema Review
用户:帮我 review 这个表结构设计
AI:Schema Review 结果:
✓ 优点:
- 使用 BIGSERIAL 而非 INT,扩展性好
- 金额使用 DECIMAL 类型正确
- 有适当的索引
⚠ 建议改进:
1. status 字段建议使用 ENUM 或 CHECK 约束
→ ALTER TABLE orders ADD CHECK (status IN ('pending', 'paid', 'shipped', 'completed', 'cancelled'));
2. 缺少 deleted_at 软删除字段
→ 订单数据不应物理删除
3. user_id 索引可加 status 组合
→ CREATE INDEX idx_orders_user_status ON orders(user_id, status);
4. order_no 生成策略需明确
→ 建议:日期前缀 + 随机数(如 20260914-ABC123)
数据迁移
生成迁移脚本
用户:给 users 表添加 phone 和 avatar_url 字段
AI:生成迁移脚本:
-- migrations/004_add_user_phone_avatar.up.sql
ALTER TABLE users
ADD COLUMN phone VARCHAR(20),
ADD COLUMN avatar_url TEXT;
CREATE INDEX idx_users_phone ON users(phone);
-- migrations/004_add_user_phone_avatar.down.sql
DROP INDEX IF EXISTS idx_users_phone;
ALTER TABLE users
DROP COLUMN IF EXISTS phone,
DROP COLUMN IF EXISTS avatar_url;
注意事项:
- phone 允许为空(现有用户未填写)
- 添加索引用于后续的手机号查询
- down 脚本提供完整回滚能力
安全迁移建议
AI 会根据数据量和变更类型给出安全建议:
AI:⚠ 安全提醒:
此迁移涉及大表变更(users 表约 100 万行)。
PostgreSQL 中 ADD COLUMN(无默认值)是轻量操作,
不会锁表。但如果添加 NOT NULL + DEFAULT:
✗ 危险写法:
ALTER TABLE users ADD COLUMN phone VARCHAR(20) NOT NULL DEFAULT '';
→ 会重写整张表,锁定数分钟
✓ 安全写法(分步):
1. ALTER TABLE users ADD COLUMN phone VARCHAR(20);
2. UPDATE users SET phone = '' WHERE phone IS NULL; -- 分批执行
3. ALTER TABLE users ALTER COLUMN phone SET NOT NULL;
4. ALTER TABLE users ALTER COLUMN phone SET DEFAULT '';
查询优化
分析慢查询
用户:这个查询很慢,帮我优化
SELECT * FROM orders WHERE user_id = 123 ORDER BY created_at DESC;
AI:查询分析:
当前执行计划:
Seq Scan on orders (cost=0.00..15234.00 rows=500000)
→ 全表扫描!缺少 user_id 索引
优化方案:
方案 1:添加索引(推荐)
CREATE INDEX idx_orders_user_created
ON orders(user_id, created_at DESC);
→ 预期:Seq Scan → Index Scan,ms 级响应
方案 2:如果只需要最新 N 条
SELECT * FROM orders
WHERE user_id = 123
ORDER BY created_at DESC
LIMIT 20;
→ 配合索引,效率极高
方案 3:避免 SELECT *
SELECT id, order_no, status, total_amount, created_at
FROM orders
WHERE user_id = 123
ORDER BY created_at DESC;
→ 减少数据传输量
综合建议:方案 1 + 方案 2 + 方案 3 一起使用
N+1 查询检测
用户:这段代码性能不好,帮我看看
AI:检测到 N+1 查询问题:
当前代码:
users := db.Find(&users) // 1 次查询
for _, u := range users {
db.Find(&u.Orders, "user_id = ?", u.ID) // N 次查询
}
→ 如果有 100 个用户,就会执行 101 次查询!
优化方案:使用 Preload 一次性加载
db.Preload("Orders").Find(&users)
→ 只需 2 次查询(1 次 users + 1 次 orders WHERE user_id IN (...))
ORM 辅助
生成 Model
用户:根据 orders 表生成 GORM model
AI:
// internal/model/order.go
type Order struct {
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
OrderNo string `gorm:"uniqueIndex;size:32;not null" json:"order_no"`
UserID int64 `gorm:"index;not null" json:"user_id"`
Status string `gorm:"size:20;not null;default:pending" json:"status"`
TotalAmount decimal.Decimal `gorm:"type:decimal(12,2);not null" json:"total_amount"`
Currency string `gorm:"size:3;not null;default:CNY" json:"currency"`
Remark *string `json:"remark,omitempty"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
PaidAt *time.Time `json:"paid_at,omitempty"`
// 关联
User *User `gorm:"foreignKey:UserID" json:"user,omitempty"`
OrderItems []OrderItem `gorm:"foreignKey:OrderID" json:"items,omitempty"`
}
func (Order) TableName() string {
return "orders"
}
生成 Repository
用户:为 Order model 生成 repository
AI:
// internal/repository/order.go
type OrderRepository struct {
db *gorm.DB
}
func NewOrderRepository(db *gorm.DB) *OrderRepository {
return &OrderRepository{db: db}
}
func (r *OrderRepository) Create(ctx context.Context, order *model.Order) error {
return r.db.WithContext(ctx).Create(order).Error
}
func (r *OrderRepository) FindByID(ctx context.Context, id int64) (*model.Order, error) {
var order model.Order
err := r.db.WithContext(ctx).
Preload("OrderItems").
First(&order, id).Error
if err != nil {
return nil, err
}
return &order, nil
}
func (r *OrderRepository) ListByUserID(ctx context.Context, userID int64, page, pageSize int) ([]model.Order, int64, error) {
var orders []model.Order
var total int64
query := r.db.WithContext(ctx).
Where("user_id = ?", userID)
query.Model(&model.Order{}).Count(&total)
err := query.
Order("created_at DESC").
Offset((page - 1) * pageSize).
Limit(pageSize).
Find(&orders).Error
return orders, total, err
}
// ... 更多方法
注意事项
- 生成的 SQL 请在执行前 review,特别是 DELETE 和 UPDATE 操作
- 迁移脚本在生产环境执行前建议先在 staging 环境验证
- 查询优化建议需要根据实际数据量和使用场景评估
- ORM 代码生成遵循项目现有的代码风格和分层架构
- 敏感数据(密码、Token)不会出现在生成的示例数据中