【问题标题】:How to delete large data from Firebird SQL database如何从 Firebird SQL 数据库中删除大数据
【发布时间】:2021-02-18 18:22:57
【问题描述】:

我有一个非常大的数据库(至少对我来说)- 超过 1 000 000 条记录,我需要删除所有时间戳低于某个值的记录。比如:

DELETE FROM table WHERE TS < 2020-01-01;

我面临的问题是,事务完成后,如果它完成了,数据库是无响应且无法使用的。如果没有上述问题,如何删除这么多记录?

我是新手,到目前为止,我只使用过具有 1000-10000 行的数据库,并且我用来删除记录的命令没有引起问题。

【问题讨论】:

  • 无响应和无法使用是什么意思?您是否有机会发出select * from table 或其他扫描大部分表格的东西?这可能表明您正在触发协作垃圾收集,这意味着执行表扫描的事务会产生从删除中清理垃圾的成本。
  • 也许你需要一个索引?
  • @Mark Rotterveel 是的,这正是我遇到的问题,或者下一次删除我尝试做的事情。我怎样才能过去呢?我应该先做DELETE 然后备份和恢复,然后再删除并再次备份和恢复?
  • @Tony1234 。 . .将要保留的数据存储在新表中通常会更好。然后截断现有表并重新插入数据。
  • @GordonLinoff Firebird 没有 truncate table 语句,因此您需要删除所有记录,这将导致更大版本的问题,因为它会产生更多垃圾来收集。

标签: sql firebird firebird2.5


【解决方案1】:

根据您在问题中的描述和您的 cmets,问题与 Firebird 中垃圾收集的工作方式有关。 Firebird 是一个所谓的Multi-Version Concurrency Control (MVCC) 数据库,您对行(记录)所做的每一次更改,包括删除,都会创建该记录的新版本,并保持以前的版本可用于在产生该记录的事务之前启动的其他事务。更改已提交。

如果在先前版本的记录中没有更多“感兴趣”的事务,则该先前版本有资格进行垃圾收集。 Firebird 有两种垃圾回收方式:cooperative(所有服务器模式都支持)和background(SuperServer 支持),以及第三种combined 模式两者都可以(这是 SuperServer 的默认设置)。

background 模式是一个清理垃圾的专用线程,如果它们看到垃圾,则由活动语句发出信号。

合作模式中,看到垃圾的语句也是必须清理垃圾的语句。当语句在大更新或删除后立即执行全表扫描时,这可能会特别昂贵。该语句不仅会查找并返回行,还会重写数据库页面以消除这些垃圾。

另见幻灯片Garbage collection mechanism and sweep in details

有一些可能的解决方案:

  1. 如果您使用的是 SuperServer,请更改策略,将firebird.conf 中的设置GCPolicy 设置为background

    此解决方案的缺点是可能需要更长的时间才能收集所有垃圾,但最大的好处是进行垃圾收集工作不会减慢事务的速度。

  2. 在提交产生大量垃圾的事务后,执行执行全表扫描的语句(例如select count(*) from table)以触发垃圾收集,使用单独的工作线程不阻塞其余进程。

    只有在没有对旧记录版本仍然感兴趣的活动事务时,此选项才真正有效。

  3. 创建一个backup的数据库(不需要恢复,除了验证备份是否正常工作)。

    默认情况下(除非您指定 -g 选项来禁用垃圾收集),gbak 工具将在备份期间执行垃圾收集。这与选项 2 具有相同的限制,因为它有效,因为 gbak 相当于 select * from table

  4. 使用gfix -sweep 对数据库执行“扫描”。

    这与前两个选项有类似的限制

  5. 对于不会导致垃圾收集速度变慢的连接,请指定连接选项isc_dpb_no_garbage_collect(详细信息因驱动程序和连接库而异)。

    如果您为所有连接指定此项,并且您的策略是合作(因为它已配置,或者您使用的是 Classic 或 SuperClassic 服务器模式),则不会发生垃圾收集,这也可能导致最终减速,因为引擎将不得不扫描更长的记录版本链。这可以通过使用前两个选项执行垃圾回收来缓解。

  6. 与其真正删除记录,不如在您的应用程序中引入软删除以将记录标记为已删除,而不是真正删除它们。

    要么永久保留这些记录,要么在以后真正删除它们,例如通过在数据库未加载时运行的计划作业,并包括之前的选项之一来触发垃圾回收。

【讨论】:

  • 感谢您的完整回答。想到的另一个问题是——当垃圾被select * from table我选择用来清理它的任何东西清理干净时,数据库的大小会缩小吗?
  • @T0ny1234 不,数据库不会收缩。空间将保持分配状态,但可重复使用以存储新记录(或现有记录的新记录版本)。在某些情况下,如果数据页完全为空,则分配给特定表的数据页可能会被释放,但这仅意味着它将被添加到将被重用的空闲页列表中。缩小数据库的唯一选择是使用 gbak 进行备份并恢复它。
  • @Mark Rotterveel 再次感谢您。
【解决方案2】:

实际上,由于垃圾收集器和工作线程之间的高度紧张,后台垃圾收集正是导致“数据库无响应”行为的原因。协作 GC 可能会减慢操作,但会保持数据库“响应”。至少对于 2.5 版。

另一个原因是有很多重复的坏索引。这样的索引通常对查询没有用,应该简单地删除。如果这不是一个选项,它们可以在删除之前停用,然后在单独的事务中重新激活(作为副作用,激活将导致完全垃圾收集)。

当然,最好的选择是保留所有数据。对于在体面的硬件上精心设计的数据库来说,1kk 条记录并不算多。

【讨论】:

  • 后台垃圾回收不应导致数据库无响应。协作机制导致它,因为接触表的语句会做额外的垃圾收集工作,如果有很多垃圾要收集,这可能会大大减慢它。
  • 更大的 RAM 缓存也有帮助,因为 Interbase 是几十年前设计的,默认情况下非常保守。但我想知道这个“子线程”是否属于一般 FB 引擎优化主题而不是这个特定的批量删除主题。
  • 是的,它不应该导致数据库无响应,但不幸的是它在某些情况下会发生。这就是为什么 Firebird 2.5 Classic Server 通常是更好的选择。 3.0 更好,4.0 更好。
猜你喜欢
  • 2013-05-18
  • 2012-03-23
  • 1970-01-01
  • 1970-01-01
  • 2014-05-09
  • 1970-01-01
  • 1970-01-01
  • 2014-07-31
  • 1970-01-01
相关资源
最近更新 更多