22 KiB
22 KiB
外卖SaaS系统 - 数据库设计
1. 数据库设计原则
1.1 命名规范
- 表名:小写字母,下划线分隔,复数形式(如:
orders,order_items) - 字段名:小写字母,下划线分隔(如:
created_at,total_amount) - 主键:统一使用
id,类型为 UUID - 外键:
表名_id(如:order_id,merchant_id) - 索引:
idx_表名_字段名(如:idx_orders_merchant_id)
1.2 通用字段
所有表都包含以下字段:
id:UUID,主键created_at:TIMESTAMP,创建时间updated_at:TIMESTAMP,更新时间deleted_at:TIMESTAMP,软删除时间(可选)tenant_id:UUID,租户ID(多租户隔离)
1.3 数据类型规范
- 金额:DECIMAL(18,2)
- 时间:TIMESTAMP WITH TIME ZONE
- 布尔:BOOLEAN
- 枚举:VARCHAR 或 INTEGER
- JSON数据:JSONB
2. 核心表结构
2.1 租户管理
tenants(租户表)
CREATE TABLE tenants (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(100) NOT NULL,
code VARCHAR(50) UNIQUE NOT NULL,
contact_name VARCHAR(50),
contact_phone VARCHAR(20),
contact_email VARCHAR(100),
status INTEGER NOT NULL DEFAULT 1, -- 1:正常 2:冻结 3:过期
subscription_plan VARCHAR(50), -- 订阅套餐
subscription_start_date TIMESTAMP WITH TIME ZONE,
subscription_end_date TIMESTAMP WITH TIME ZONE,
max_merchants INTEGER DEFAULT 10, -- 最大商家数
max_orders_per_day INTEGER DEFAULT 1000, -- 每日订单限额
settings JSONB, -- 租户配置
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_tenants_code ON tenants(code);
CREATE INDEX idx_tenants_status ON tenants(status);
2.2 商家管理
merchants(商家表)
CREATE TABLE merchants (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
name VARCHAR(100) NOT NULL,
logo_url VARCHAR(500),
description TEXT,
contact_phone VARCHAR(20),
contact_person VARCHAR(50),
business_license VARCHAR(100), -- 营业执照号
status INTEGER NOT NULL DEFAULT 1, -- 1:正常 2:休息 3:停业
rating DECIMAL(3,2) DEFAULT 0, -- 评分
total_sales INTEGER DEFAULT 0, -- 总销量
settings JSONB, -- 商家配置
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_merchants_tenant_id ON merchants(tenant_id);
CREATE INDEX idx_merchants_status ON merchants(status);
merchant_stores(门店表)
CREATE TABLE merchant_stores (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
merchant_id UUID NOT NULL REFERENCES merchants(id),
name VARCHAR(100) NOT NULL,
address VARCHAR(500) NOT NULL,
latitude DECIMAL(10,7), -- 纬度
longitude DECIMAL(10,7), -- 经度
phone VARCHAR(20),
business_hours JSONB, -- 营业时间 {"monday": {"open": "09:00", "close": "22:00"}}
delivery_range INTEGER DEFAULT 3000, -- 配送范围(米)
min_order_amount DECIMAL(18,2) DEFAULT 0, -- 起送价
delivery_fee DECIMAL(18,2) DEFAULT 0, -- 配送费
status INTEGER NOT NULL DEFAULT 1,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_merchant_stores_merchant_id ON merchant_stores(merchant_id);
CREATE INDEX idx_merchant_stores_location ON merchant_stores USING GIST(point(longitude, latitude));
2.3 菜品管理
categories(菜品分类表)
CREATE TABLE categories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
merchant_id UUID NOT NULL REFERENCES merchants(id),
name VARCHAR(50) NOT NULL,
sort_order INTEGER DEFAULT 0,
status INTEGER NOT NULL DEFAULT 1,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_categories_merchant_id ON categories(merchant_id);
dishes(菜品表)
CREATE TABLE dishes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
merchant_id UUID NOT NULL REFERENCES merchants(id),
category_id UUID REFERENCES categories(id),
name VARCHAR(100) NOT NULL,
description TEXT,
image_url VARCHAR(500),
price DECIMAL(18,2) NOT NULL,
original_price DECIMAL(18,2), -- 原价
unit VARCHAR(20) DEFAULT '份', -- 单位
stock INTEGER, -- 库存(NULL表示不限)
sales_count INTEGER DEFAULT 0, -- 销量
rating DECIMAL(3,2) DEFAULT 0, -- 评分
sort_order INTEGER DEFAULT 0,
status INTEGER NOT NULL DEFAULT 1, -- 1:上架 2:下架
tags JSONB, -- 标签 ["热销", "新品"]
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_dishes_merchant_id ON dishes(merchant_id);
CREATE INDEX idx_dishes_category_id ON dishes(category_id);
CREATE INDEX idx_dishes_status ON dishes(status);
dish_specs(菜品规格表)
CREATE TABLE dish_specs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
dish_id UUID NOT NULL REFERENCES dishes(id),
name VARCHAR(50) NOT NULL, -- 规格名称(如:大份、小份)
price DECIMAL(18,2) NOT NULL,
stock INTEGER,
status INTEGER NOT NULL DEFAULT 1,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_dish_specs_dish_id ON dish_specs(dish_id);
2.4 用户管理
users(用户表)
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
phone VARCHAR(20) UNIQUE NOT NULL,
nickname VARCHAR(50),
avatar_url VARCHAR(500),
gender INTEGER, -- 0:未知 1:男 2:女
birthday DATE,
balance DECIMAL(18,2) DEFAULT 0, -- 余额
points INTEGER DEFAULT 0, -- 积分
status INTEGER NOT NULL DEFAULT 1,
last_login_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_users_phone ON users(phone);
user_addresses(用户地址表)
CREATE TABLE user_addresses (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id),
contact_name VARCHAR(50) NOT NULL,
contact_phone VARCHAR(20) NOT NULL,
province VARCHAR(50),
city VARCHAR(50),
district VARCHAR(50),
address VARCHAR(500) NOT NULL,
house_number VARCHAR(50), -- 门牌号
latitude DECIMAL(10,7),
longitude DECIMAL(10,7),
is_default BOOLEAN DEFAULT FALSE,
label VARCHAR(20), -- 标签:家、公司等
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_user_addresses_user_id ON user_addresses(user_id);
2.5 订单管理
orders(订单表)
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
order_no VARCHAR(50) UNIQUE NOT NULL, -- 订单号
merchant_id UUID NOT NULL REFERENCES merchants(id),
store_id UUID NOT NULL REFERENCES merchant_stores(id),
user_id UUID NOT NULL REFERENCES users(id),
-- 收货信息
delivery_address VARCHAR(500) NOT NULL,
delivery_latitude DECIMAL(10,7),
delivery_longitude DECIMAL(10,7),
contact_name VARCHAR(50) NOT NULL,
contact_phone VARCHAR(20) NOT NULL,
-- 金额信息
dish_amount DECIMAL(18,2) NOT NULL, -- 菜品金额
delivery_fee DECIMAL(18,2) DEFAULT 0, -- 配送费
package_fee DECIMAL(18,2) DEFAULT 0, -- 打包费
discount_amount DECIMAL(18,2) DEFAULT 0, -- 优惠金额
total_amount DECIMAL(18,2) NOT NULL, -- 总金额
actual_amount DECIMAL(18,2) NOT NULL, -- 实付金额
-- 订单状态
status INTEGER NOT NULL DEFAULT 1, -- 1:待支付 2:待接单 3:制作中 4:待配送 5:配送中 6:已完成 7:已取消
payment_status INTEGER DEFAULT 0, -- 0:未支付 1:已支付 2:已退款
payment_method VARCHAR(20), -- 支付方式
payment_time TIMESTAMP WITH TIME ZONE,
-- 时间信息
estimated_delivery_time TIMESTAMP WITH TIME ZONE, -- 预计送达时间
accepted_at TIMESTAMP WITH TIME ZONE, -- 接单时间
cooking_at TIMESTAMP WITH TIME ZONE, -- 开始制作时间
delivered_at TIMESTAMP WITH TIME ZONE, -- 送达时间
completed_at TIMESTAMP WITH TIME ZONE, -- 完成时间
cancelled_at TIMESTAMP WITH TIME ZONE, -- 取消时间
remark TEXT, -- 备注
cancel_reason TEXT, -- 取消原因
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_orders_tenant_id ON orders(tenant_id);
CREATE INDEX idx_orders_order_no ON orders(order_no);
CREATE INDEX idx_orders_merchant_id ON orders(merchant_id);
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);
order_items(订单明细表)
CREATE TABLE order_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
order_id UUID NOT NULL REFERENCES orders(id),
dish_id UUID NOT NULL REFERENCES dishes(id),
dish_name VARCHAR(100) NOT NULL, -- 冗余字段,防止菜品被删除
dish_image_url VARCHAR(500),
spec_id UUID REFERENCES dish_specs(id),
spec_name VARCHAR(50),
price DECIMAL(18,2) NOT NULL, -- 单价
quantity INTEGER NOT NULL, -- 数量
amount DECIMAL(18,2) NOT NULL, -- 小计
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_order_items_order_id ON order_items(order_id);
CREATE INDEX idx_order_items_dish_id ON order_items(dish_id);
2.6 配送管理
delivery_drivers(配送员表)
CREATE TABLE delivery_drivers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
merchant_id UUID REFERENCES merchants(id), -- NULL表示平台配送员
name VARCHAR(50) NOT NULL,
phone VARCHAR(20) UNIQUE NOT NULL,
id_card VARCHAR(18), -- 身份证号
vehicle_type VARCHAR(20), -- 车辆类型:电动车、摩托车
vehicle_number VARCHAR(20), -- 车牌号
status INTEGER NOT NULL DEFAULT 1, -- 1:空闲 2:配送中 3:休息 4:离线
current_latitude DECIMAL(10,7), -- 当前位置
current_longitude DECIMAL(10,7),
rating DECIMAL(3,2) DEFAULT 0,
total_deliveries INTEGER DEFAULT 0, -- 总配送单数
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_delivery_drivers_merchant_id ON delivery_drivers(merchant_id);
CREATE INDEX idx_delivery_drivers_status ON delivery_drivers(status);
delivery_tasks(配送任务表)
CREATE TABLE delivery_tasks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
order_id UUID NOT NULL REFERENCES orders(id),
driver_id UUID REFERENCES delivery_drivers(id),
pickup_address VARCHAR(500) NOT NULL, -- 取餐地址
pickup_latitude DECIMAL(10,7),
pickup_longitude DECIMAL(10,7),
delivery_address VARCHAR(500) NOT NULL, -- 送餐地址
delivery_latitude DECIMAL(10,7),
delivery_longitude DECIMAL(10,7),
distance INTEGER, -- 配送距离(米)
estimated_time INTEGER, -- 预计时长(分钟)
status INTEGER NOT NULL DEFAULT 1, -- 1:待分配 2:待取餐 3:配送中 4:已送达 5:异常
assigned_at TIMESTAMP WITH TIME ZONE, -- 分配时间
picked_at TIMESTAMP WITH TIME ZONE, -- 取餐时间
delivered_at TIMESTAMP WITH TIME ZONE, -- 送达时间
delivery_fee DECIMAL(18,2) DEFAULT 0, -- 配送费
remark TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_delivery_tasks_order_id ON delivery_tasks(order_id);
CREATE INDEX idx_delivery_tasks_driver_id ON delivery_tasks(driver_id);
CREATE INDEX idx_delivery_tasks_status ON delivery_tasks(status);
2.7 支付管理
payments(支付记录表)
CREATE TABLE payments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
order_id UUID NOT NULL REFERENCES orders(id),
user_id UUID NOT NULL REFERENCES users(id),
payment_no VARCHAR(50) UNIQUE NOT NULL, -- 支付单号
payment_method VARCHAR(20) NOT NULL, -- 支付方式:wechat、alipay、balance
amount DECIMAL(18,2) NOT NULL,
status INTEGER NOT NULL DEFAULT 0, -- 0:待支付 1:支付中 2:成功 3:失败 4:已退款
third_party_no VARCHAR(100), -- 第三方支付单号
paid_at TIMESTAMP WITH TIME ZONE,
callback_data JSONB, -- 回调数据
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_payments_order_id ON payments(order_id);
CREATE INDEX idx_payments_payment_no ON payments(payment_no);
CREATE INDEX idx_payments_user_id ON payments(user_id);
refunds(退款记录表)
CREATE TABLE refunds (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
order_id UUID NOT NULL REFERENCES orders(id),
payment_id UUID NOT NULL REFERENCES payments(id),
refund_no VARCHAR(50) UNIQUE NOT NULL,
amount DECIMAL(18,2) NOT NULL,
reason TEXT,
status INTEGER NOT NULL DEFAULT 0, -- 0:待审核 1:退款中 2:成功 3:失败
third_party_no VARCHAR(100),
refunded_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_refunds_order_id ON refunds(order_id);
CREATE INDEX idx_refunds_payment_id ON refunds(payment_id);
2.8 营销管理
coupons(优惠券表)
CREATE TABLE coupons (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
merchant_id UUID REFERENCES merchants(id), -- NULL表示平台券
name VARCHAR(100) NOT NULL,
type INTEGER NOT NULL, -- 1:满减券 2:折扣券 3:代金券
discount_type INTEGER NOT NULL, -- 1:固定金额 2:百分比
discount_value DECIMAL(18,2) NOT NULL, -- 优惠值
min_order_amount DECIMAL(18,2) DEFAULT 0, -- 最低消费
max_discount_amount DECIMAL(18,2), -- 最大优惠金额(折扣券用)
total_quantity INTEGER NOT NULL, -- 总数量
received_quantity INTEGER DEFAULT 0, -- 已领取数量
used_quantity INTEGER DEFAULT 0, -- 已使用数量
valid_start_time TIMESTAMP WITH TIME ZONE NOT NULL,
valid_end_time TIMESTAMP WITH TIME ZONE NOT NULL,
status INTEGER NOT NULL DEFAULT 1, -- 1:正常 2:停用
description TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_coupons_merchant_id ON coupons(merchant_id);
CREATE INDEX idx_coupons_status ON coupons(status);
user_coupons(用户优惠券表)
CREATE TABLE user_coupons (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id),
coupon_id UUID NOT NULL REFERENCES coupons(id),
status INTEGER NOT NULL DEFAULT 1, -- 1:未使用 2:已使用 3:已过期
used_order_id UUID REFERENCES orders(id),
received_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
used_at TIMESTAMP WITH TIME ZONE,
expired_at TIMESTAMP WITH TIME ZONE NOT NULL
);
CREATE INDEX idx_user_coupons_user_id ON user_coupons(user_id);
CREATE INDEX idx_user_coupons_coupon_id ON user_coupons(coupon_id);
CREATE INDEX idx_user_coupons_status ON user_coupons(status);
2.9 评价管理
reviews(评价表)
CREATE TABLE reviews (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
order_id UUID NOT NULL REFERENCES orders(id),
user_id UUID NOT NULL REFERENCES users(id),
merchant_id UUID NOT NULL REFERENCES merchants(id),
rating INTEGER NOT NULL, -- 评分 1-5
taste_rating INTEGER, -- 口味评分
package_rating INTEGER, -- 包装评分
delivery_rating INTEGER, -- 配送评分
content TEXT,
images JSONB, -- 评价图片
is_anonymous BOOLEAN DEFAULT FALSE,
reply_content TEXT, -- 商家回复
reply_at TIMESTAMP WITH TIME ZONE,
status INTEGER NOT NULL DEFAULT 1, -- 1:正常 2:隐藏
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_reviews_order_id ON reviews(order_id);
CREATE INDEX idx_reviews_user_id ON reviews(user_id);
CREATE INDEX idx_reviews_merchant_id ON reviews(merchant_id);
2.10 系统管理
system_users(系统用户表)
CREATE TABLE system_users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID REFERENCES tenants(id), -- NULL表示平台管理员
merchant_id UUID REFERENCES merchants(id), -- NULL表示租户管理员
username VARCHAR(50) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
real_name VARCHAR(50),
phone VARCHAR(20),
email VARCHAR(100),
role_id UUID REFERENCES roles(id),
status INTEGER NOT NULL DEFAULT 1,
last_login_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_system_users_username ON system_users(username);
CREATE INDEX idx_system_users_tenant_id ON system_users(tenant_id);
roles(角色表)
CREATE TABLE roles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID REFERENCES tenants(id),
name VARCHAR(50) NOT NULL,
code VARCHAR(50) NOT NULL,
description TEXT,
permissions JSONB, -- 权限列表
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_roles_tenant_id ON roles(tenant_id);
operation_logs(操作日志表)
CREATE TABLE operation_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID REFERENCES tenants(id),
user_id UUID,
user_type VARCHAR(20), -- system_user, merchant_user, customer
module VARCHAR(50), -- 模块
action VARCHAR(50), -- 操作
description TEXT,
ip_address VARCHAR(50),
user_agent TEXT,
request_data JSONB,
response_data JSONB,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_operation_logs_tenant_id ON operation_logs(tenant_id);
CREATE INDEX idx_operation_logs_user_id ON operation_logs(user_id);
CREATE INDEX idx_operation_logs_created_at ON operation_logs(created_at);
3. 数据库索引策略
3.1 主键索引
- 所有表使用UUID作为主键,自动创建主键索引
3.2 外键索引
- 所有外键字段创建索引,提升关联查询性能
3.3 业务索引
- 订单号、支付单号等唯一业务字段创建唯一索引
- 状态字段创建普通索引
- 时间字段(created_at)创建索引,支持时间范围查询
3.4 复合索引
-- 订单查询常用复合索引
CREATE INDEX idx_orders_merchant_status_created ON orders(merchant_id, status, created_at DESC);
-- 用户订单查询
CREATE INDEX idx_orders_user_status_created ON orders(user_id, status, created_at DESC);
3.5 地理位置索引
-- 使用PostGIS扩展支持地理位置查询
CREATE EXTENSION IF NOT EXISTS postgis;
-- 门店位置索引
CREATE INDEX idx_merchant_stores_location ON merchant_stores
USING GIST(ST_MakePoint(longitude, latitude));
4. 数据库优化
4.1 分区策略
-- 订单表按月分区
CREATE TABLE orders_2024_01 PARTITION OF orders
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
CREATE TABLE orders_2024_02 PARTITION OF orders
FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');
4.2 物化视图
-- 商家统计物化视图
CREATE MATERIALIZED VIEW merchant_statistics AS
SELECT
m.id as merchant_id,
m.name,
COUNT(DISTINCT o.id) as total_orders,
SUM(o.actual_amount) as total_revenue,
AVG(r.rating) as avg_rating
FROM merchants m
LEFT JOIN orders o ON m.id = o.merchant_id AND o.status = 6
LEFT JOIN reviews r ON m.id = r.merchant_id
GROUP BY m.id, m.name;
CREATE UNIQUE INDEX ON merchant_statistics(merchant_id);
4.3 查询优化建议
- 避免SELECT *,只查询需要的字段
- 使用EXPLAIN分析查询计划
- 合理使用JOIN,避免过多关联
- 大数据量查询使用分页
- 使用prepared statement防止SQL注入
5. 数据备份策略
5.1 备份方案
- 全量备份:每天凌晨2点执行
- 增量备份:每4小时执行一次
- WAL归档:实时归档,支持PITR
5.2 备份脚本示例
#!/bin/bash
# 全量备份
pg_dump -h localhost -U postgres -d takeout_saas -F c -f /backup/full_$(date +%Y%m%d).dump
# 保留最近30天的备份
find /backup -name "full_*.dump" -mtime +30 -delete
6. 数据迁移
6.1 EF Core Migrations
# 添加迁移
dotnet ef migrations add InitialCreate --project TakeoutSaaS.Infrastructure
# 更新数据库
dotnet ef database update --project TakeoutSaaS.Infrastructure
6.2 版本控制
- 所有数据库变更通过Migration管理
- Migration文件纳入版本控制
- 生产环境变更需要审核