数据库占用内存过高如何解决

前言

大家好!我是【提前退休的java猿】(抖音同号)👏

昨天有位粉丝私信我"数据库占用内存过高,如何优化?",今天就和大家分享一下如何解决数据库占用内存过高的问题

数据库内存占用过高

要解决问题肯定就得找到问题的原因?

使用内存监控工具:通过top、htop(Linux)监控数据库进程(如mysqld、postgres)的内存占用,结合数据库自带工具(如 MySQL 的SHOW ENGINE INNODB STATUS)分析内存使用细节

一、排查内存过高的原因

首先然后想到的当然就是SQL写法上的优化,其次就是数据库配置,或者系统架构的问题了,比如并发太高数据库的活跃线程比较高等问题

哪些SQL会占用很高的内存呢?

  • 大结果集查询,查询大量的字段(select *)且没有分页
  • join查询使用不当。join连查询如果表数据量大也是非常占用内存的。join的底层实现有好几种算法,想了解的可以参考: sql 中谨慎使用多表join
  • 是否有很多长事务,导致内存始终得不到释放(比如索引失效等问题)

排查方法我们可以通过SQL命令查看此时活跃得线程的查询信息(PGSQl为例):

SQL 复制代码
SELECT 
    pid,                -- 进程ID
    usename AS user,    -- 执行查询的用户
    datname AS db,      -- 连接的数据库
    client_addr,        -- 客户端IP地址
    application_name,   -- 应用程序名称
    backend_start,      -- 后端进程启动时间
    query_start,        -- 查询开始时间
    state_change,       -- 状态变更时间
    state,              -- 会话状态(active/running/idle等)
    wait_event_type,    -- 等待事件类型
    wait_event,         -- 具体等待事件
    query               -- 当前执行的SQL语句(可能被截断)
FROM 
    pg_stat_activity
WHERE 
    state = 'active'    -- 只显示活跃状态的查询
ORDER BY 
    query_start DESC;   -- 按查询开始时间倒序排列

通过查看目前执行的SQL情况,来排查是SQL不规范或者是SQL需要优化。如果定位到SQL符合上面的情况,要优化就自然而然的就很简单了。

查看需要的字段,分页处理;多次查询,内存组装,减少数据库压力和内存;优化代码逻辑减少事务执行时间。

数据库配置

只能说数据库配置,能优化数据库对占用问题,并且不是解决根本问题方式吧。还是带大家看一下,配置层面对内存有什么影响以及怎么去解决这个。

  • MySQL/InnoDB 示例

    • 链表查询缓存join_buffer_size :没有索引的join查询时候,会把数据查询到内存中匹配。这个就是控制内存的缓存大小的。可以排查是否是设置得太大,可以降低这个缓存配置

    • 缓冲池(innodb_buffer_pool_size) :这是 InnoDB 最核心的内存消耗项,建议设置为系统可用内存的 50%-70%(避免占用过高导致系统 OOM)。

      例如:innodb_buffer_pool_size = 8G(若系统内存为 16G)。

    • 连接数(max_connections) :过多连接会占用大量内存,需根据实际并发量调整,避免设置过大(根据业务调整测试吧)。(设置得太大,并发高的时候全都压到数据库了)

    • 临时表内存(tmp_table_size、max_heap_table_size) :限制内存临时表大小,超过则自动转为磁盘表,避免内存溢出。

      例如:tmp_table_size = 64Mmax_heap_table_size = 64M

    • 查询缓存(query_cache_size) :MySQL 8.0 已移除该功能,低版本若开启,建议关闭(query_cache_type = 0),避免缓存失效时的内存消耗。

  • PostgreSQL 示例

    • 共享缓冲区(shared_buffers) :建议设置为系统内存的 25%(默认较小,需手动调大)。
    • 工作内存(work_mem) :每个查询的排序、哈希操作使用的内存,根据并发查询数调整(如work_mem = 16M,避免单个查询占用过多)。
    • 最大连接数(max_connections) :默认 100,过高会导致内存激增,建议结合连接池(如 PgBouncer)控制。

架构上做调整

如果SQL和配置都排查了或者优化了,还是出现占用内存过高。估计就是并发太高了。这个时候就需要在架构上做相应的调整了!

  • 做限流处理,或者使用消息队列流量削峰,减少数据库压力,从而减少内存

  • 使用缓存如redis,缓存热点数据。从而减少数据库内存占用问题

  • 对于超大表,可通过分区表(按时间、地域拆分)或分库分表(如 ShardingSphere)分散数据量,降低单库内存压力。

总结

解决数据库内存过高的核心思路是:先定位原因(查询、配置、连接等),再针对性优化(调参数、改查询、控连接) ,同时结合监控工具长期跟踪内存变化,避免问题复发。

如果是高并发场景,那就需要调整 系统架构,包括引入中间件、限流、缓存等等措施,同时数据库架构也需要做相应的调整(如读写分离、分库分表),从根本上降低单节点内存压力。

相关推荐
掘根29 分钟前
【MySQL进阶】三大范式
数据库·mysql·oracle
深度学习04071 小时前
【Linux服务器】-MySQL数据库参数调优
linux·服务器·数据库
brzhang3 小时前
颠覆你对代码的认知:当程序和数据只剩下一棵树,能读懂这篇文章的人估计全球也不到 100 个人
前端·后端·架构
躲在云朵里`4 小时前
SpringBoot的介绍和项目搭建
java·spring boot·后端
别致的影分身4 小时前
MySQL InnoDB 存储引擎
数据库·mysql
喵个咪4 小时前
Golang微服框架Kratos与它的小伙伴系列 - 分布式事务框架 - DTM
后端·微服务·go
PythonicCC4 小时前
Django ORM系统
数据库·django
brzhang4 小时前
我见过了太多做智能音箱做成智障音箱的例子了,今天我就来说说如何做意图识别
前端·后端·架构
晴空月明5 小时前
结构型模式-架构解耦与扩展实践
后端
WanderInk6 小时前
在递归中为什么用 `int[]` 而不是 `int`?——揭秘 Java 参数传递的秘密
java·后端·算法