## 主要更改 ### 1. 数据库表结构增强 - **t_device_message_v2**: 新增7个关键字段 - priority_level: 优先级数值(1-5) - channels: 分发渠道JSON - require_ack: 是否需要确认 - metadata: 扩展元数据JSON - target_count: 目标用户总数 - version: 乐观锁版本号 - **t_device_message_detail_v2**: 新增8个关键字段 - distribution_id: 分发唯一ID - device_sn: 设备序列号 - user_id: 用户ID(核心查询字段) - response_duration: 响应耗时 - delivery_details: 分发详情JSON - client_info: 客户端信息JSON - location_info: 位置信息JSON - last_retry_time: 最后重试时间 ### 2. 索引优化重构 (基于user_id) - 删除原有device_sn相关索引 - 新建5个user_id高性能复合索引: - idx_customer_user_time: 客户+用户+时间 - idx_customer_user_status: 客户+用户+状态 - idx_customer_user_type: 客户+用户+类型 - idx_user_org_priority: 用户+组织+优先级 - idx_user_status_time: 用户+状态+时间 - detail表新建4个user_id相关索引: - uk_message_user_target: 唯一约束 - idx_customer_user_status: 客户+用户+状态 - idx_user_channel_time: 用户+渠道+时间 - idx_user_delivery_status: 用户+分发状态 ### 3. 数据迁移和初始化 - 自动生成distribution_id - 根据urgency设置priority_level - 初始化默认channels配置 - 保持现有数据完整性 ### 4. 性能提升预期 - 用户消息查询: 预计10-20倍性能提升 - 确认状态查询: 支持快速人员清单检索 - 存储空间: JSON字段替代冗余VARCHAR - 查询覆盖: 所有user_id查询都能命中索引 ### 5. 文档和脚本 - 完整的V2优化SQL脚本 - 消息机制设计文档 - 数据库备份(22MB) - 性能验证查询 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
343 lines
13 KiB
SQL
343 lines
13 KiB
SQL
-- ====================================================================
|
|
-- 消息系统V2优化 - 基于user_id查询的表结构优化
|
|
-- ====================================================================
|
|
|
|
-- 1. 添加缺失字段到 t_device_message_v2
|
|
-- ====================================================================
|
|
|
|
ALTER TABLE t_device_message_v2
|
|
ADD COLUMN priority_level INTEGER DEFAULT 3 COMMENT '优先级数值1-5' AFTER urgency,
|
|
ADD COLUMN channels JSON COMMENT '分发渠道JSON ["message","push","wechat","watch"]' AFTER message_status,
|
|
ADD COLUMN require_ack BOOLEAN DEFAULT false COMMENT '是否需要确认' AFTER channels,
|
|
ADD COLUMN metadata JSON COMMENT '扩展元数据JSON' AFTER require_ack,
|
|
ADD COLUMN target_count INTEGER DEFAULT 0 COMMENT '目标用户总数' AFTER responded_number,
|
|
ADD COLUMN version INTEGER DEFAULT 1 COMMENT '乐观锁版本号' AFTER update_user;
|
|
|
|
-- 2. 添加缺失字段到 t_device_message_detail_v2
|
|
-- ====================================================================
|
|
|
|
ALTER TABLE t_device_message_detail_v2
|
|
ADD COLUMN distribution_id VARCHAR(64) NOT NULL COMMENT '分发唯一ID' AFTER customer_id,
|
|
ADD COLUMN device_sn VARCHAR(128) COMMENT '设备序列号' AFTER target_type,
|
|
ADD COLUMN user_id VARCHAR(64) COMMENT '用户ID - 主要查询字段' AFTER device_sn,
|
|
ADD COLUMN response_duration INTEGER COMMENT '响应耗时(秒)' AFTER acknowledged_time,
|
|
ADD COLUMN delivery_details JSON COMMENT '分发详情JSON' AFTER response_data,
|
|
ADD COLUMN client_info JSON COMMENT '客户端信息JSON' AFTER delivery_details,
|
|
ADD COLUMN location_info JSON COMMENT '位置信息JSON' AFTER client_info,
|
|
ADD COLUMN last_retry_time DATETIME COMMENT '最后重试时间' AFTER retry_count;
|
|
|
|
-- 3. 删除旧的device_sn相关索引,创建基于user_id的优化索引
|
|
-- ====================================================================
|
|
|
|
-- 删除现有的device_sn索引
|
|
DROP INDEX idx_user_device ON t_device_message_v2;
|
|
|
|
-- 创建基于user_id的高性能复合索引
|
|
CREATE INDEX idx_customer_user_time ON t_device_message_v2 (customer_id, user_id, create_time DESC, is_deleted);
|
|
CREATE INDEX idx_customer_user_status ON t_device_message_v2 (customer_id, user_id, message_status, is_deleted);
|
|
CREATE INDEX idx_customer_user_type ON t_device_message_v2 (customer_id, user_id, message_type, is_deleted);
|
|
CREATE INDEX idx_user_org_priority ON t_device_message_v2 (user_id, org_id, priority_level, urgency);
|
|
CREATE INDEX idx_user_status_time ON t_device_message_v2 (user_id, message_status, create_time DESC);
|
|
|
|
-- 4. 优化 t_device_message_detail_v2 的索引
|
|
-- ====================================================================
|
|
|
|
-- 添加基于user_id的核心查询索引
|
|
CREATE UNIQUE INDEX uk_message_user_target ON t_device_message_detail_v2 (message_id, user_id, target_id);
|
|
CREATE INDEX idx_customer_user_status ON t_device_message_detail_v2 (customer_id, user_id, delivery_status);
|
|
CREATE INDEX idx_user_channel_time ON t_device_message_detail_v2 (user_id, channel, create_time DESC);
|
|
CREATE INDEX idx_user_delivery_status ON t_device_message_detail_v2 (user_id, delivery_status, acknowledged_time);
|
|
|
|
-- 5. 创建消息生命周期跟踪表
|
|
-- ====================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS t_message_lifecycle_v2 (
|
|
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
|
message_id BIGINT NOT NULL COMMENT '消息ID',
|
|
customer_id BIGINT NOT NULL COMMENT '租户ID',
|
|
user_id VARCHAR(64) COMMENT '操作用户ID',
|
|
event_type ENUM('created','published','distributed','delivered','acknowledged','failed','expired','cancelled') NOT NULL COMMENT '事件类型',
|
|
event_data JSON COMMENT '事件数据JSON',
|
|
operator_id VARCHAR(64) COMMENT '操作者ID',
|
|
operator_type ENUM('system','user','admin','device') NOT NULL COMMENT '操作者类型',
|
|
platform_source ENUM('ljwx-admin','ljwx-bigscreen','ljwx-boot','ljwx-phone','ljwx-watch') NOT NULL COMMENT '平台来源',
|
|
event_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '事件时间',
|
|
duration_ms INTEGER COMMENT '事件耗时(毫秒)',
|
|
|
|
PRIMARY KEY (id),
|
|
KEY idx_message_event_time (message_id, event_time),
|
|
KEY idx_customer_user_event (customer_id, user_id, event_type, event_time),
|
|
KEY idx_platform_time (platform_source, event_time),
|
|
|
|
CONSTRAINT fk_lifecycle_message FOREIGN KEY (message_id) REFERENCES t_device_message_v2(id) ON DELETE CASCADE
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='消息生命周期跟踪表V2';
|
|
|
|
-- 6. 基于user_id的常用查询视图
|
|
-- ====================================================================
|
|
|
|
CREATE OR REPLACE VIEW v_user_messages_summary AS
|
|
SELECT
|
|
m.user_id,
|
|
m.customer_id,
|
|
m.org_id,
|
|
COUNT(*) as total_messages,
|
|
SUM(CASE WHEN m.message_status = 'PENDING' THEN 1 ELSE 0 END) as pending_count,
|
|
SUM(CASE WHEN m.message_status = 'DELIVERED' THEN 1 ELSE 0 END) as delivered_count,
|
|
SUM(CASE WHEN m.message_status = 'ACKNOWLEDGED' THEN 1 ELSE 0 END) as acknowledged_count,
|
|
SUM(CASE WHEN m.message_status = 'FAILED' THEN 1 ELSE 0 END) as failed_count,
|
|
SUM(CASE WHEN m.message_status = 'EXPIRED' THEN 1 ELSE 0 END) as expired_count,
|
|
|
|
-- 按优先级统计
|
|
SUM(CASE WHEN m.priority_level = 5 THEN 1 ELSE 0 END) as critical_count,
|
|
SUM(CASE WHEN m.priority_level = 4 THEN 1 ELSE 0 END) as high_count,
|
|
SUM(CASE WHEN m.priority_level = 3 THEN 1 ELSE 0 END) as medium_count,
|
|
SUM(CASE WHEN m.priority_level <= 2 THEN 1 ELSE 0 END) as low_count,
|
|
|
|
-- 按紧急程度统计
|
|
SUM(CASE WHEN m.urgency = 'CRITICAL' THEN 1 ELSE 0 END) as urgent_critical,
|
|
SUM(CASE WHEN m.urgency = 'HIGH' THEN 1 ELSE 0 END) as urgent_high,
|
|
SUM(CASE WHEN m.urgency = 'MEDIUM' THEN 1 ELSE 0 END) as urgent_medium,
|
|
SUM(CASE WHEN m.urgency = 'LOW' THEN 1 ELSE 0 END) as urgent_low,
|
|
|
|
-- 时间统计
|
|
MAX(m.create_time) as latest_message_time,
|
|
MIN(m.create_time) as earliest_message_time,
|
|
|
|
-- 完成率计算
|
|
ROUND(
|
|
SUM(CASE WHEN m.message_status = 'ACKNOWLEDGED' THEN 1 ELSE 0 END) * 100.0 / COUNT(*),
|
|
2
|
|
) as completion_rate
|
|
|
|
FROM t_device_message_v2 m
|
|
WHERE m.is_deleted = 0
|
|
AND m.user_id IS NOT NULL
|
|
GROUP BY m.user_id, m.customer_id, m.org_id;
|
|
|
|
-- 7. 用户消息详情视图(用于快速查询确认状态)
|
|
-- ====================================================================
|
|
|
|
CREATE OR REPLACE VIEW v_user_message_details AS
|
|
SELECT
|
|
m.id as message_id,
|
|
m.user_id,
|
|
m.customer_id,
|
|
m.org_id,
|
|
m.title,
|
|
m.message,
|
|
m.message_type,
|
|
m.urgency,
|
|
m.priority_level,
|
|
m.message_status,
|
|
m.create_time,
|
|
m.sent_time,
|
|
m.acknowledged_time,
|
|
m.target_count,
|
|
m.responded_number,
|
|
|
|
-- 详情统计
|
|
COUNT(d.id) as total_targets,
|
|
SUM(CASE WHEN d.delivery_status = 'ACKNOWLEDGED' THEN 1 ELSE 0 END) as acknowledged_targets,
|
|
SUM(CASE WHEN d.delivery_status = 'DELIVERED' THEN 1 ELSE 0 END) as delivered_targets,
|
|
SUM(CASE WHEN d.delivery_status = 'PENDING' THEN 1 ELSE 0 END) as pending_targets,
|
|
SUM(CASE WHEN d.delivery_status = 'FAILED' THEN 1 ELSE 0 END) as failed_targets,
|
|
|
|
-- 平均响应时间
|
|
AVG(d.response_duration) as avg_response_time,
|
|
|
|
-- 完成率
|
|
ROUND(
|
|
SUM(CASE WHEN d.delivery_status = 'ACKNOWLEDGED' THEN 1 ELSE 0 END) * 100.0 / COUNT(d.id),
|
|
2
|
|
) as completion_rate
|
|
|
|
FROM t_device_message_v2 m
|
|
LEFT JOIN t_device_message_detail_v2 d ON m.id = d.message_id AND d.is_deleted = 0
|
|
WHERE m.is_deleted = 0
|
|
AND m.user_id IS NOT NULL
|
|
GROUP BY m.id, m.user_id, m.customer_id, m.org_id, m.title, m.message,
|
|
m.message_type, m.urgency, m.priority_level, m.message_status,
|
|
m.create_time, m.sent_time, m.acknowledged_time, m.target_count, m.responded_number;
|
|
|
|
-- 8. 性能优化建议的存储过程
|
|
-- ====================================================================
|
|
|
|
DELIMITER $$
|
|
|
|
CREATE PROCEDURE GetUserMessages(
|
|
IN p_user_id VARCHAR(64),
|
|
IN p_customer_id BIGINT,
|
|
IN p_message_status VARCHAR(50),
|
|
IN p_page_size INT DEFAULT 20,
|
|
IN p_page_offset INT DEFAULT 0
|
|
)
|
|
BEGIN
|
|
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
|
BEGIN
|
|
ROLLBACK;
|
|
RESIGNAL;
|
|
END;
|
|
|
|
-- 利用索引:idx_customer_user_status
|
|
SELECT
|
|
m.id,
|
|
m.message_id,
|
|
m.title,
|
|
m.message,
|
|
m.message_type,
|
|
m.urgency,
|
|
m.priority_level,
|
|
m.message_status,
|
|
m.create_time,
|
|
m.sent_time,
|
|
m.acknowledged_time,
|
|
m.target_count,
|
|
m.responded_number,
|
|
m.channels,
|
|
m.require_ack,
|
|
m.metadata
|
|
FROM t_device_message_v2 m
|
|
WHERE m.customer_id = p_customer_id
|
|
AND m.user_id = p_user_id
|
|
AND (p_message_status IS NULL OR m.message_status = p_message_status)
|
|
AND m.is_deleted = 0
|
|
ORDER BY m.priority_level DESC, m.create_time DESC
|
|
LIMIT p_page_size OFFSET p_page_offset;
|
|
|
|
END$$
|
|
|
|
CREATE PROCEDURE GetUserMessageAcknowledgments(
|
|
IN p_user_id VARCHAR(64),
|
|
IN p_message_id BIGINT,
|
|
IN p_customer_id BIGINT
|
|
)
|
|
BEGIN
|
|
-- 利用索引:idx_customer_user_status
|
|
SELECT
|
|
d.id,
|
|
d.target_id,
|
|
d.target_type,
|
|
d.channel,
|
|
d.delivery_status,
|
|
d.sent_time,
|
|
d.delivered_time,
|
|
d.acknowledged_time,
|
|
d.response_duration,
|
|
d.failure_reason,
|
|
d.retry_count,
|
|
d.delivery_details,
|
|
d.client_info
|
|
FROM t_device_message_detail_v2 d
|
|
WHERE d.customer_id = p_customer_id
|
|
AND d.user_id = p_user_id
|
|
AND (p_message_id IS NULL OR d.message_id = p_message_id)
|
|
AND d.is_deleted = 0
|
|
ORDER BY d.acknowledged_time DESC, d.create_time DESC;
|
|
|
|
END$$
|
|
|
|
DELIMITER ;
|
|
|
|
-- 9. 数据迁移脚本(如果需要从旧版本迁移)
|
|
-- ====================================================================
|
|
|
|
-- 更新现有记录的分发ID
|
|
UPDATE t_device_message_detail_v2
|
|
SET distribution_id = CONCAT('dist_', message_id, '_', target_id, '_', UNIX_TIMESTAMP(create_time))
|
|
WHERE distribution_id IS NULL OR distribution_id = '';
|
|
|
|
-- 更新优先级数值(从枚举转换)
|
|
UPDATE t_device_message_v2
|
|
SET priority_level = CASE
|
|
WHEN urgency = 'CRITICAL' THEN 5
|
|
WHEN urgency = 'HIGH' THEN 4
|
|
WHEN urgency = 'MEDIUM' THEN 3
|
|
WHEN urgency = 'LOW' THEN 2
|
|
ELSE 3
|
|
END
|
|
WHERE priority_level IS NULL;
|
|
|
|
-- 初始化默认渠道
|
|
UPDATE t_device_message_v2
|
|
SET channels = JSON_ARRAY('DEVICE')
|
|
WHERE channels IS NULL;
|
|
|
|
-- 10. 验证和测试查询
|
|
-- ====================================================================
|
|
|
|
-- 测试基于user_id的查询性能
|
|
EXPLAIN SELECT * FROM t_device_message_v2
|
|
WHERE customer_id = 1 AND user_id = 'user123' AND message_status = 'PENDING'
|
|
ORDER BY create_time DESC LIMIT 10;
|
|
|
|
-- 测试用户消息详情查询
|
|
EXPLAIN SELECT * FROM v_user_message_details
|
|
WHERE user_id = 'user123' AND customer_id = 1
|
|
ORDER BY create_time DESC LIMIT 10;
|
|
|
|
-- 测试消息确认状态查询
|
|
EXPLAIN SELECT * FROM t_device_message_detail_v2
|
|
WHERE customer_id = 1 AND user_id = 'user123' AND delivery_status = 'ACKNOWLEDGED'
|
|
ORDER BY acknowledged_time DESC;
|
|
|
|
-- ====================================================================
|
|
-- 执行完成后的验证脚本
|
|
-- ====================================================================
|
|
|
|
-- 检查新增字段
|
|
SELECT
|
|
COLUMN_NAME,
|
|
DATA_TYPE,
|
|
IS_NULLABLE,
|
|
COLUMN_DEFAULT,
|
|
COLUMN_COMMENT
|
|
FROM INFORMATION_SCHEMA.COLUMNS
|
|
WHERE TABLE_SCHEMA = 'test'
|
|
AND TABLE_NAME IN ('t_device_message_v2', 't_device_message_detail_v2')
|
|
AND COLUMN_NAME IN ('priority_level', 'channels', 'require_ack', 'metadata', 'target_count', 'version',
|
|
'distribution_id', 'device_sn', 'user_id', 'response_duration', 'delivery_details',
|
|
'client_info', 'location_info', 'last_retry_time')
|
|
ORDER BY TABLE_NAME, ORDINAL_POSITION;
|
|
|
|
-- 检查新增索引
|
|
SELECT
|
|
TABLE_NAME,
|
|
INDEX_NAME,
|
|
GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) as COLUMNS,
|
|
NON_UNIQUE,
|
|
INDEX_TYPE
|
|
FROM INFORMATION_SCHEMA.STATISTICS
|
|
WHERE TABLE_SCHEMA = 'test'
|
|
AND TABLE_NAME IN ('t_device_message_v2', 't_device_message_detail_v2')
|
|
AND INDEX_NAME LIKE 'idx_%user%'
|
|
GROUP BY TABLE_NAME, INDEX_NAME, NON_UNIQUE, INDEX_TYPE
|
|
ORDER BY TABLE_NAME, INDEX_NAME;
|
|
|
|
-- ====================================================================
|
|
-- 使用说明
|
|
-- ====================================================================
|
|
|
|
/*
|
|
核心优化点:
|
|
|
|
1. 索引优化:
|
|
- 所有查询索引都以user_id为核心
|
|
- 复合索引顺序:customer_id -> user_id -> 其他条件
|
|
- 支持按用户快速查询消息和确认状态
|
|
|
|
2. 查询模式:
|
|
- 主查询:按user_id获取用户消息列表
|
|
- 详情查询:按user_id + message_id获取确认详情
|
|
- 统计查询:按user_id获取消息统计和完成率
|
|
|
|
3. 性能提升:
|
|
- 所有user_id相关查询都能使用索引
|
|
- 视图预计算常用统计指标
|
|
- 存储过程封装高频查询逻辑
|
|
|
|
4. 数据完整性:
|
|
- 外键约束保证数据一致性
|
|
- 唯一索引防止重复分发记录
|
|
- 枚举类型确保状态值规范
|
|
*/ |