我有一个 MySQL 表,大约有 150 万条记录,表大小为 1.3GB
我在该表中使用软删除机制,这意味着我有一列 deleted_at
指示该行是否已被删除以及何时被删除。如果记录未删除,则 deleted_at
值为 NULL
在这 150 万条记录中,只有 30K 条记录没有被软删除。这意味着它们会被频繁访问,而其他记录则很少被访问,但在某些情况下确实如此。
因此该表被大量使用并查询未删除的记录,有时还查询软删除的记录。
我有一个 deleted_at
记录的 BTREE
索引类型(基数为 35K)。随着时间的推移, table 变得越来越重,显然这不是一个可扩展的解决方案。
表引擎是MyISAM
。大多数其他表都是 InnoDB,但此表使用存储过程进行大量查询,当我更改为 InnoDB 时,查询速度要慢得多。
我正在寻找一种不涉及硬件更改的解决方案。当前的硬件足以使该表具有良好的性能,但是一旦该表增长得更多,情况就不会如此。
我想到的事情:
- 分区,但我无法使用
分区
,因为某些列已建立FULL TEXT
索引。 - 将数据拆分为两个表。一种用于已删除的行,一种用于频繁访问和查询的未删除行。此更改需要大量基础设施更改,因此我并不急于执行此操作。
- 创建一个新表,每 10/20 分钟与原始表同步一次,而不是拆分,并且仅包含未删除的行。这将需要对基础设施进行小的改动,而且维护也更加容易和安全。拆分成两个表可能会因查询失败而导致记录丢失,因为“DELETE”操作实际上会将行从一个表移动到另一个表,因此需要复杂的机制
我还有什么其他选择?我可以优先考虑 MySQL 表中的某些行吗?明智的内存。
我有 10.3.20-MariaDB
和 32GB RAM
最佳答案
MyISAM 不缓存行,它只缓存索引。它依赖于文件系统缓存来缓冲行。
因此您可以尝试确保至少索引已完全加载到缓存中:
- 增加
key_buffer_size
,使其至少与该表的 MyISAM 索引一样大。使用SHOW TABLE STATUS
找出索引大小。 - 如果您有多个 MyISAM 表,您可能需要专门为此表指定一个键缓存。请参阅CACHE INDEX .
- 在启动时将索引预加载到键缓存中。请参阅LOAD INDEX INTO CACHE .
您可能还需要考虑针对您的查询量身定制的多列索引。就像如果您有一个查询WHERE user_id = 1234 AND returned_at IS NULL
,您应该在(user_id,deleted_at)
上创建一个索引。
您需要哪些索引取决于您要优化的查询。
坦率地说,我会拆分该表,以便删除的行位于第二个表中。这将使您的表大小减少 98%,并且可能会使查询运行得足够快,以至于您不再需要使用 MyISAM。
关于mysql - 优化 1.5m 条记录的 mysql 表,其中大部分被软删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60030019/