讲师中心 微信公众号
AI工具推荐 视频效率加速

如何在聊天系统实战中使用MySQL保存历史聊天记录?

落明酱_2230

落明酱_2230

发布时间:2026-11-03 06:41:32

|

965人浏览过

|

来源于php中文网

原创

直接INSERT存消息在高并发下会导致主键冲突、时间戳精度不足排序错乱、缺失会话关联字段,且无索引时查询性能骤降;必须建表时设计session_id、sender_id/receiver_id、created_at(DATETIME(6))三核心字段,并建对应联合索引。

如何在聊天系统实战中使用mysql保存历史聊天记录?

为什么不能直接用 INSERT INTO chat_log 无脑存消息

直接每条消息都 INSERT 看似简单,但高并发下会迅速暴露问题:主键冲突(比如客户端重发)、时间戳精度不足导致排序错乱、缺失会话上下文关联字段。更麻烦的是,chat_log 表如果没加合适的索引,查某两个用户之间的全部对话会变慢得肉眼可见——不是几毫秒,是几百毫秒起步。

关键不是“能不能存”,而是“存完能不能稳准快地取回来”。所以必须从建表那一刻就考虑三个核心字段:session_id(标识一次完整对话)、sender_id/receiver_id(谁发给谁)、created_at(带微秒精度的 DATETIME(6))。

实操建议:

  • 用 UUID 或服务端生成的 bigint 做 session_id,别依赖前端传;前端传的容易伪造或重复
  • created_at 必须用 DATETIME(6),MySQL 5.6.4+ 支持,避免同秒内多条消息顺序颠倒
  • 联合索引至少要覆盖:(session_id, created_at) 和 (sender_id, receiver_id, created_at)

怎么处理撤回、编辑、已读状态这类“消息元操作”

很多人把撤回当成“删掉记录”,这是错的。真实场景中,你得保留原始消息快照,只标记状态变更——否则审计、调试、数据对账全崩。MySQL 里最稳妥的做法是加一个 status 字段(TINYINT),值为 0(正常)、1(已撤回)、2(已编辑)、3(已读)。

注意:已读状态通常不和消息存在同一张表,因为读写频率差异太大。单独建 chat_read_status 表,字段至少含 session_id、user_id、last_read_seq(最后读到第几条),用 ON DUPLICATE KEY UPDATE 更新更安全。

常见错误现象:

  • 用 DELETE FROM chat_log WHERE id = ? 处理撤回 → 日志丢失,无法追溯
  • 把已读时间存在 chat_log 表里 → 每次用户点开聊天就全表更新,锁表风险高
  • 用 TEXT 存消息内容却不加 CHARSET=utf8mb4 → 表情符号存成 ???

分页查历史记录时,LIMIT offset, size 为什么越往后越卡

当用户往上翻到第 100 页(offset=5000),MySQL 得先扫描前 5000 行再返回后 50 条,I/O 和 CPU 成倍涨。这不是代码问题,是 SQL 设计缺陷。

MySQL8 CRM Schema Design Expert
MySQL8 CRM Schema Design Expert

面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。

下载

正确做法是“游标分页”(cursor-based pagination):用上一页最后一条的 created_at 和 id 作为条件,例如:

SELECT * FROM chat_log 
WHERE session_id = ? AND (created_at, id) < (?, ?) 
ORDER BY created_at DESC, id DESC 
LIMIT 50;

前提是 (created_at, id) 有联合索引,且 id 是主键(自增或唯一)。这样每次都是范围查询,性能稳定在毫秒级。

额外提醒:

  • 别用 SELECT * 查历史,只选必要字段(如 content、sender_id、created_at)
  • 客户端传来的 session_id 必须做白名单校验或权限检查,否则可能越权读别人聊天
  • 如果单条消息超 1MB(比如传了大图 base64),别硬塞进 MySQL,存对象存储 URL + 元数据

MySQL 主从延迟导致“刚发的消息查不到”怎么破

读写分离架构下,用户发完消息立刻去从库查,大概率查不到——因为主从同步有几十到几百毫秒延迟。这不是 bug,是 MySQL 复制机制决定的。

解决方案不是关掉从库,而是分场景路由:

  • 用户自己刚发送的消息,强制走主库查(加 /*FORCE_MASTER*/ 注释或用中间件标记)
  • 查别人发来的消息、历史归档类请求,才走从库
  • 对一致性要求极高的操作(如撤回、已读确认),所有读写都走主库

如果你用的是 ProxySQL 或 ShardingSphere,这些路由策略能配死;如果直连,就得在 DAO 层手动控制连接源。别指望应用层加 SLEEP(100) 等同步——既不准又伤性能。

最容易被忽略的一点:哪怕用了游标分页,如果上一页最后一条消息是在主从延迟窗口内写入的,从库查出来的“最后 created_at”可能是旧值,导致漏数据。所以游标字段必须包含主键 id,它不受时间精度和同步延迟影响。

热门AI工具

更多
WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

创客贴AI

创客贴AI是一款AI图像与设计工具,AI辅助的智能在线设计工具。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

2453

2023.06.20

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

1479

2023.06.21

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

875

2023.07.18

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

3472

2023.07.19

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

5988

2023.07.25

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

1279

2023.08.08

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

6251

2023.08.11

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

5382

2023.08.14

Uvicorn 报错与问题解决教程
Uvicorn 报错与问题解决教程

本专题汇总了Uvicorn服务器常见问题与报错解决的教程合集,涵盖启动失败、端口占用、模块导入错误、事件循环冲突及热重载失效等典型故障的排查思路。同时整理了多进程与Worker配置、SSL/HTTPS证书报错、跨域与代理配置等实战解决方案,助你快速定位并解决Uvicorn运行中的各类问题。

0

2026.11.02

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 193人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn