CREATE TABLE users (
user_id BIGINT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
avatar VARCHAR(255),
status TINYINT COMMENT '0-离线,1-在线',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_username (username)
);
CREATE TABLE conversations (
conversation_id BIGINT PRIMARY KEY,
conversation_type TINYINT NOT NULL COMMENT '1-单聊,2-群聊',
title VARCHAR(100) COMMENT '群聊标题',
creator_id BIGINT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_creator (creator_id),
INDEX idx_updated (updated_at)
) ENGINE=InnoDB;
CREATE TABLE conversation_participants (
id BIGINT PRIMARY KEY,
conversation_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
join_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_read_message_id BIGINT COMMENT '最后阅读的消息ID',
unread_count INT DEFAULT 0 COMMENT '未读消息数',
is_muted TINYINT DEFAULT 0 COMMENT '是否静音',
INDEX idx_conversation_user (conversation_id, user_id),
INDEX idx_user_conversation (user_id, conversation_id),
FOREIGN KEY (conversation_id) REFERENCES conversations(conversation_id),
FOREIGN KEY (user_id) REFERENCES users(user_id)
) ENGINE=InnoDB;
CREATE TABLE messages (
message_id BIGINT PRIMARY KEY,
conversation_id BIGINT NOT NULL,
sender_id BIGINT NOT NULL,
content TEXT,
content_type TINYINT DEFAULT 1 COMMENT '1-文本,2-图片,3-文件,4-链接',
status TINYINT DEFAULT 1 COMMENT '1-发送中,2-已发送,3-已送达,4-已读',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_conversation_created (conversation_id, created_at),
INDEX idx_sender (sender_id),
FOREIGN KEY (conversation_id) REFERENCES conversations(conversation_id),
FOREIGN KEY (sender_id) REFERENCES users(user_id)
) ENGINE=InnoDB PARTITION BY RANGE (UNIX_TIMESTAMP(created_at)) (
PARTITION p2023 VALUES LESS THAN (UNIX_TIMESTAMP('2024-01-01')),
PARTITION p2024 VALUES LESS THAN (UNIX_TIMESTAMP('2025-01-01')),
PARTITION pmax VALUES LESS THAN MAXVALUE
);
CREATE TABLE message_read_status (
id BIGINT PRIMARY KEY,
message_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
read_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_message_user (message_id, user_id),
INDEX idx_user_message (user_id, message_id),
FOREIGN KEY (message_id) REFERENCES messages(message_id),
FOREIGN KEY (user_id) REFERENCES users(user_id)
) ENGINE=InnoDB;
-- 获取用户会话列表(按最后更新时间排序)
SELECT
c.conversation_id,
c.conversation_type,
c.title,
m.content AS last_message,
m.created_at AS last_message_time,
cp.unread_count
FROM
conversation_participants cp
JOIN
conversations c ON cp.conversation_id = c.conversation_id
LEFT JOIN
messages m ON m.message_id = (
SELECT message_id
FROM messages
WHERE conversation_id = c.conversation_id
ORDER BY created_at DESC
LIMIT 1
)
WHERE
cp.user_id = ?
ORDER BY
m.created_at DESC;
优化点: - 使用LEFT JOIN和子查询获取最新一条消息 - 添加复合索引 (user_id, conversation_id) 和 (conversation_id, created_at)
-- 分页获取会话消息
SELECT
m.message_id,
m.sender_id,
u.username AS sender_name,
m.content,
m.content_type,
m.status,
m.created_at
FROM
messages m
JOIN
users u ON m.sender_id = u.user_id
WHERE
m.conversation_id = ?
ORDER BY
m.created_at DESC
LIMIT ?, ?;
优化点: - 使用分区表按时间范围分区 - 添加复合索引 (conversation_id, created_at) - 使用延迟关联优化深度分页
-- 使用触发器或定期任务更新未读计数
UPDATE conversation_participants cp
SET cp.unread_count = (
SELECT COUNT(*)
FROM messages m
WHERE m.conversation_id = cp.conversation_id
AND m.created_at > (
SELECT read_at
FROM message_read_status
WHERE user_id = cp.user_id
AND message_id = cp.last_read_message_id
)
)
WHERE cp.user_id = ?;
读写分离:将消息查询和会话列表查询分离到不同数据库实例
缓存策略:
消息分区策略:
异步处理:
数据分片:
索引优化:
通过以上设计,可以高效支持CSDN私信功能的会话列表展示、消息历史查询和实时消息推送等核心功能,同时保证系统在大规模用户下的性能表现。