# 外卖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(租户表) ```sql 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(商家表) ```sql 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(门店表) ```sql 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(菜品分类表) ```sql 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(菜品表) ```sql 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(菜品规格表) ```sql 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(用户表) ```sql 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(用户地址表) ```sql 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(订单表) ```sql 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(订单明细表) ```sql 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(配送员表) ```sql 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(配送任务表) ```sql 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(支付记录表) ```sql 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(退款记录表) ```sql 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(优惠券表) ```sql 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(用户优惠券表) ```sql 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(评价表) ```sql 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(系统用户表) ```sql 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(角色表) ```sql 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(操作日志表) ```sql 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 复合索引 ```sql -- 订单查询常用复合索引 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 地理位置索引 ```sql -- 使用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 分区策略 ```sql -- 订单表按月分区 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 物化视图 ```sql -- 商家统计物化视图 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 备份脚本示例 ```bash #!/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 ```bash # 添加迁移 dotnet ef migrations add InitialCreate --project TakeoutSaaS.Infrastructure # 更新数据库 dotnet ef database update --project TakeoutSaaS.Infrastructure ``` ### 6.2 版本控制 - 所有数据库变更通过Migration管理 - Migration文件纳入版本控制 - 生产环境变更需要审核