MyISAM/InnoDB 以何种有效方式从文件中删除特定文本?

In what efficient way does MyISAM/InnoDB deletes specific text from a file?

请在将问题标记为重复之前阅读整个问题。

我知道我们只有一种方法可以从 C 中的文件中删除特定文本,即重写整个文件,除了我们想要的文本 delete.But 如果我们有一个包含数千或数百万行文本的文件。现在由于 MyISAM 是一个必须提高效率的存储引擎,因为它要用于数百万条记录并且它是用 C 语言制作的,那么它如何在不重写整个文件的情况下实现这一点?即我问的是 MyISAM 的开发人员使用的技术从文件中删除特定文本而不重写它。

和DOS一样,不是"deleted",而是"marked as deleted",以至于后面的操作,删除的东西好像都没有了

MyISAM:

  • 标记记录的第一个字节,表示是"deleted"。
  • 从每个索引中删除适当的条目。

InnoDB:

  • 转到包含要删除的行的块(在数据 BTree 中,由 PRIMARY KEY 索引);将其标记为已删除。
  • 将内容添加到 redo/undo 日志中——以防后续 ROLLBACK 恢复该行。
  • 向更改缓冲区添加一个条目,以便索引查找不会找到该行。
  • 最终将更改缓冲区条目刷新到实际索引。
  • 最终清除块外的数据记录。

在任何一个引擎中,只有很少的 IOP(BTree 下钻、读取、写入、日志记录)来删除行。 IOP 的实际数量取决于缓存——由于将此删除与 table.

上的其他操作相结合

MyISAM的数据是流文件;该代码将 "seek" + 读取或写入一条记录。

MyISAM 的索引是 BTree 并缓存在 "key_buffer"(1KB 块)中; InnoDB 的数据和索引是 BTree,缓存在 "buffer_pool"(16KB 块)中。所有操作都是seek + read/write一个块。

InnoDB redo/undo 我认为日志是流式传输的。

InnoDB的"double write"缓冲区是一个被冗余写入的块。这是针对 "torn page" 的 ACID 保护,其中块在断电期间被写入一半。大多数磁盘上的操作单元是一个512字节"sector"; MyISAM/InnoDB的单位是这样的几个。

中长运行

那么,如果一条记录只被标记为已删除,磁盘 space 是否可以恢复?我强调磁盘 space 而不是 "memory" RAM,因为 RAM 仅用作缓存。

好吧,这取决于。如果您 "churning" 数据 -- 删除和插入 -- 然后 DELETE 释放的 space 可用于 INSERT。但是,由于记录的布局方式,INSERT 可能会或可能不会重用最近由 DELETE 释放的 space。但是,在长 运行 中,插入将填充删除留下的 'holes'。但是...

BTrees 本身就有一个小问题。每个节点都是一个固定大小的块。做了几次删除后,固定大小已经不是sh运行k了。在插入过多之后,该块 "split" 分为两个块(相同、固定、大小)。尽管如此,随着时间的推移,BTree 将被吸引到大约 69% 的空间。也就是说,最初的 69 个完整块将(经过大量改动后)达到大约 100 个块的稳定状态,同时仍包含相同数量的记录。

所以,a table 会增长,但不会缩小。但增长仅限于实际数据大小的某些倍数。缩水呢?...

在 MyISAM 和 InnoDB 中,都有自动方法 "defragment" 并将浪费的 space 还给操作系统。但是,有一个 SQL 语句可以做到这一点。但是不要使用它;这是不值得的努力。它会创建一个新的 table,复制所有数据,重建索引并将 table 重命名为原来的名称。很多努力;几乎没有什么好处。

另一件事...如果两个 'adjacent' BTree 块少于半满,这些块将被合并。 (这释放了一个块以供在给定 table 中重用,但不会将其返回给 OS。)

"large companies" 是做什么的?答:"Nothing."我以前也做过这样的工作,所以我可以谈谈经验。在 100 个系统上的 10,000 table 秒中,我确定了 只有 2 种值得进行碎片整理的情况。而且只有每月一次。还有 MyISAM,而不是 InnoDB。你今天不应该使用 MyISAM。