当前位置: 首页 > news >正文

数据库表的性能优化过程

问题背景

做一个数据库表查看、标注与分析的工具软件。

是数据库中表的信息(information_schema.tables);是的数据字典文档,存储在本地文件中;是对的额外标注信息,存储在另一个数据库中。每一条,最多关联到一条和一条。

现在想搜索。前端向后端提供3个参数,搜索关键词列表、当前页码、每页条数;后端的搜索逻辑是,如果一条完整数据(++)包含所有搜索关键词,则将加入搜索结果中。

的数量目前为6000+,要做到秒级搜索。

初步实现

因为跨数据源,所以不能简单连表查询。

对于每个,查出、,然后将、、中要搜索的字段值取出来,用空格隔开拼接为字符串,形如"Table字段值 Documentation字段值 Annotation字段值",我们称之为(搜索键)。如果每个关键词都包含在中,则将加入搜索结果。

搜索时,先获取所有,然后遍历每个,获取并判断是否加入搜索结果。

为了提高速度,用Redis缓存对应的。

分析数据情况:

  • 只增、不删、不改,因此,搜索时要重新获取所有,确保搜索到新;不必考虑驱逐(evict)的缓存。
  • 不增、不删、不改,因此,不必考虑驱逐的缓存。
  • 增、删、改,因此,要在增删改之后驱逐对应的缓存,确保搜索到的最新信息。

实测结果:

  • 实现了功能,支持同时按、、的字段搜索。
  • 有性能问题,即使缓存已经全部完成,但每次搜索都要耗时30s左右,原因是6000+个遍历从Redis获取,每次耗时1~15ms,累计耗时非常长。

第一次性能优化

优化缓存策略。

获取所有后,构建(→),然后将缓存,这样,下一次搜索时,只需要从Redis获取一次,提高传输效率。

为了确保搜索到新,缓存时将列表的长度作为缓存键,如果新增了,则不会命中缓存,而是重新构建。

为了减少构建的时间,仍然保留单个的缓存,仍然在增删改之后驱逐单个的缓存,但不同的是,还要同时驱逐的缓存。

实测结果:

  • 性能提升明显,在缓存全部完成的情况下,搜索耗时降至1.3s左右。
  • 仍然有性能问题,对一个做了增删改,会驱逐整个缓存,重建就又回到了遍历的情况,仍然要耗时30s左右。

第二次性能优化

优化缓存策略。

取消单个的缓存,只缓存。

搜索时,要获取。先获取现有的缓存(固定缓存键,不再使用列表长度作为缓存键;没有缓存则取得空Map),然后遍历,如果不在中,则计算并放入。这样,第一次搜索时会计算每个的,后续搜索就只需要计算新的。

增删改后,要更新。先获取现有的缓存,然后重新计算指定的并放入。这样,无需每次都重建整个。

实测结果:增删改后再搜索,耗时降至1.3s左右。

第三次性能优化

优化缓存实现方式。

既然现在只需要简单地缓存一个,那么不一定要用Redis。

使用Redis作为缓存(RedisCacheManager),虽然内网通信快,但仍有网络开销。实测平均1092.9ms。

使用Map作为缓存(ConcurrentMapCacheManager),其他代码完全不变。实测平均968.3ms。

修改代码,直接用类中的Map字段作为缓存,省去缓存管理器的开销。实测平均915.2ms。

可见,性能有提升,但幅度不大。由于软件在开发中,要频繁重新运行,Redis能保持缓存,Map不能,因此保持上一版方案不做修改。

第四次性能优化

第三次优化其实是盲目的,应该要用事实找出性能瓶颈。

对搜索过程计时分析发现,一次耗时1105ms的搜索,其中获取所有耗时1028ms,占比93%,是绝对的性能瓶颈。

思路1:先只获取所有表名,而不是对象,如果表名对应的匹配,再获取。实测发现,如果匹配的表名很多(例如关键词列表为空时),则即使有表名→的缓存(Redis实现),逐个获取也远远慢于直接从数据库一次性获取。因此,此思路不可行

思路2:只增、不删、不改,因此可以考虑增量获取。缓存列表,每次获取时跳过缓存的长度,只获取增量部分。然而,information_schema.tables中没有id,无法保证新一定排在最后。因此,此思路不可行

思路3:获取所有说到底只是为了搜索到新,如果能知道什么时候新增了,就可以放心地使用列表的缓存,或者从数据库重新获取。那么怎么知道?由于只增,所以可以用的数量判断。缓存列表,每次先从数据库查出数量(比直接查出列表明显更快),如果数量与缓存一致,则用缓存,否则查库。实测,此思路可行

实现思路3后,再次计时分析。无新增时,搜索耗时降至360ms左右(只查库数量);有新增时,耗时升至1.5s左右(查库数量+列表)。由于搜索的频率远远高于新增,因此,总体性能提升显著。

总结

经过数次性能优化,在满足功能的前提下,搜索时间从30s左右降至稳定0.4s左右,效果显著。0.4s已经没有缓慢感,性能优化工作可以结束了。

从上述优化过程可见,做优化要因地制宜,具体问题具体分析,选择合适的策略;优化效果的衡量要以实测结果为准。

http://www.jsqmd.com/news/573825/

相关文章:

  • S型速度曲线在PLC控制中的应用:以信捷XD pro为例的实战教程
  • Python全栈入门到实战【进阶篇 6】面向对象高级特性:抽象类与接口
  • 高频诱导塑料焊接技术演进与2026年优质厂商深度评估指南 - 2026年企业推荐榜
  • 【深度学习新浪潮】具身智能技术在自动驾驶汽车上的最新研发进展与应用探索
  • 深入解析PLL锁相环:从基础原理到高频应用实战
  • AI驱动的Vue3应用开发平台深入探究(二十二):CLI与工具链之开发与生产工作流
  • OpenClaw+Qwen2.5-VL-7B省钱方案:自建多模态接口替代高价API
  • Pixel Aurora Engine应用场景:独立开发者低成本构建像素IP资产库
  • 智能体(Agent)工作流设计:让Pixel Dream Workshop自主完成多轮创作
  • 2024年医学图像合成技术全景:从CNN到Diffusion模型的跨模态生成实战解析
  • 2026年比较好的大型刨花机厂家综合对比分析 - 品牌宣传支持者
  • 拼多多商品数据采集避坑指南:从权限申请到接口调用的完整流程
  • OpenClaw+Qwen2.5-VL-7B省钱方案:自建多模态接口替代GPT-4V
  • 曾经我和大模型交流业务实现记录
  • OpenClaw技能扩展实战:用Qwen3-4B镜像部署Markdown文章生成器
  • AI在测试中的应用:从测试用例生成到缺陷预测
  • FastAPI异步:SQLAlchemy 2.0 + AsyncSession 的异步数据库实践
  • 百川2-13B-4bits量化模型+OpenClaw:法律文书审查助手
  • 【网络层-IP数据报】
  • 人工智能辅助答辩必备:10款高效工具(含爱毕业aibiye)及模板评测
  • 从Java全栈工程师视角看Web开发的实战与思考
  • 数字图像处理中的m邻接:如何避免8邻接的歧义陷阱(附Python代码示例)
  • AI读脸术如何对接API?Flask服务封装部署教程
  • 计算机毕业设计:Python 二手车数据分析可视化系统 Flask框架 可视化 时间序列预测算法 逻辑回归 requests 爬虫 大数据(建议收藏)✅
  • 【深度强化学习】OpenAI Gym实战:从零构建智能体与环境交互
  • WeChatExporter:零代码基础也能轻松备份微信聊天记录的终极方案
  • 新手福音:通过快马平台零代码基础理解qun329群聊应用开发
  • OpenClaw飞书机器人集成:Kimi-VL-A3B-Thinking多模态问答助手实战
  • Qwen2.5-VL图文推理教程:Ollama中实现‘看截图→写SQL→查数据库’闭环
  • nli-distilroberta-base模型服务化:基于WSL的高效本地开发环境搭建