如何压缩 MS Access 数据库

Posted

技术标签:

【中文标题】如何压缩 MS Access 数据库【英文标题】:How to compress an MS Access database 【发布时间】:2010-08-07 01:52:11 【问题描述】:

我有一个 70MB 的 .mdb 文件。

删除文件中包含的所有记录后,大小仍为 70MB。

如何使我的.mdb 文件更小?

【问题讨论】:

做了一些修改。赌了几兆。似乎是最有可能的计量单位。不会真正影响问题的结果。 我只是没有得到这个问题的批评。我去了原始问题的来源,并且完全清楚被问到的内容,尽管编辑确实提高了它的清晰度。从一开始就是一个真正的问题。其次,关于数据库维护的不明确涉及编程的问题在 SO 上是允许的,因为它们无处不在,所以我看不出它怎么一定是超级用户的问题。对我来说,它看起来像一个灰色区域——在 SU 上这也是一个好的问题,但我认为它不属于 SO。 【参考方案1】:

曾经存在的每个数据库引擎都需要对其进行定期维护操作,以优化数据存储并恢复闲置空间。例如,在 xBase 时代,您运行了一个 PACK 命令来删除已删除的行。在 SQL Server 上,出于同样的原因,您可以运行脚本来缩小实际数据文件。

为什么每个数据库引擎都这样做?

因为如果每次写入数据库都必须以优化的顺序重写整个文件,这将对性能造成巨大影响。考虑一个将每个数据表存储在单独文件中的数据库。如果一个表有 10000 条记录,并且您删除了第 5000 条记录,为了摆脱松弛空间,您必须重写整个数据文件的后半部分。相反,每个数据库都使用某种形式将已使用的空间标记为未使用和可丢弃,以便下次在数据表上运行优化操作。

Jet/ACE 在这方面与任何其他数据库引擎没有什么不同,任何使用 Jet/ACE 数据库作为数据存储的应用程序都应该安排定期维护操作,包括备份和压缩。

在 Jet/ACE 中存在一些服务器数据库引擎中不存在的问题。具体来说,除非所有用户都关闭了与数据文件的连接,否则您无法压缩。在服务器数据库中,用户连接到数据库引擎的服务器端进程,而服务器端恶魔是存储数据的实际数据文件的唯一“用户”。因此,服务器恶魔可以决定何时执行优化和维护例程,因为它完全控制数据文件何时使用或不使用。

Access 应用程序的一个常见问题是用户会在他们的计算机上打开他们的应用程序并离开办公室一天,这意味着当您运行压缩操作时,例如在凌晨 2:00,文件仍然打开并且你不能运行它(因为 compact 替换了原始文件)。遇到此问题的大多数 Access 应用程序程序员要么容忍这种夜间维护偶尔失败(卷影副本仍允许文件备份,但不能保证备份副本将处于 100% 内部一致状态) ,或者他们将设计其 Access 应用程序以在适当的时间终止以允许夜间维护操作。我自己都做过。

在非 Access 应用程序中,存在相同的问题,但必须以不同的方式解决。对于 Web 应用程序来说,这是一个问题,但总的来说,我会说任何搅动数据足以需要压缩包的 Web 应用程序都是 Jet/ACE 数据存储完全不合适的。

现在,关于 COMPACT ON CLOSE:

任何人都不应该使用它。

曾经。

当它真正发挥作用时,它是无用的,而且非常危险。

它没有用,因为没有适当架构的生产环境供用户打开后端——如果它是 Access 应用程序,它应该被拆分,用户只打开前端,如果它是 Web应用程序,用户不会直接与数据文件交互。所以在这两种情况下,没有人会触发 COMPACT ON CLOSE,所以你浪费了你的时间来打开它。

其次,即使有人偶尔触发它,它也只有在该用户是唯一打开数据库的用户时才会起作用。正如我上面所说,如果有其他用户打开它,它就不能被压缩,所以这也不起作用——只有当触发它的用户具有独占访问权限时,COMPACT ON CLOSE 才能运行。

但最糟糕的是,COMPACT ON CLOSE 很危险,如果它运行会导致实际数据丢失。这是因为 Jet/ACE 数据库可能处于某些状态,其中内部结构不正常,但仍然可以访问所有数据。当在该状态下运行压缩/修复操作时,数据可能会丢失。这是一种极为罕见的情况,但可能性很小。

关键是 COMPACT ON CLOSE 不是有条件的,并且没有提示询问您是否要运行它。你没有机会在它运行之前进行备份,所以如果你打开它并且当你的数据库处于非常罕见的状态时它就会启动,你可能会丢失数据,否则你可以恢复你没有运行压缩操作。

因此,简而言之,对 Jet/ACE 和压缩有任何了解的人都不会打开 COMPACT ON CLOSE。

对于单个用户,您可以根据需要进行压缩。

对于共享应用程序,某种计划的维护脚本是最好的,通常在文件服务器上运行一夜。该脚本将备份文件,然后运行压缩文件。这是一个用 VBScript 编写的非常简单的脚本,而且很容易安排。

最后,如果您的应用程序经常删除大量记录,在大多数情况下,这表明存在设计错误。在常规生产使用中添加和删除的记录是临时数据,不属于您的主数据文件,无论从逻辑上还是从实用上来说。

我所有的生产应用程序都有一个临时数据库作为架构的一部分,所有临时表都存储在那里。我从不费心压缩临时数据库。如果由于某种原因由于临时数据库中的膨胀而导致性能陷入困境,我只需将临时数据库的原始空副本复制到旧数据库之上,因为除了临时数据库之外没有任何数据。这减少了前端或后端的流失和膨胀,并大大降低了后端数据文件上必要压缩的频率。

关于如何压缩的问题,有多种选择:

    在 Access UI 中,您可以压缩当前打开的数据库(工具 | 数据库实用程序)。但是,这不允许您将备份作为该过程的一部分,并且在压缩之前备份总是一个好主意,以防万一出现问题。

    在 Access UI 中,您可以压缩打开的数据库。这个从现有文件压缩到新文件,所以当你完成后,你必须重命名原始文件和新压缩文件(以获得新名称)。 FILE OPEN 对话框询问您要从哪个文件进行压缩,此时您可以重命名文件,因此您可以将其作为手动过程的一部分进行。

    在代码中,您可以使用 DAO DBEngine.CompactDatabase 方法来完成这项工作。这可以在 Access VBA、VBScript 或任何可以使用 COM 的环境中使用。您负责在您的代码中执行备份和重命名文件等操作。

    代码中的另一个选项是 JRO(Jet & Replication Objects),但它没有提供 DAO 尚不具备的紧凑操作。 JRO 是作为一个单独的库创建的,用于处理 ADO 本身不支持的特定于 Jet 的功能,因此如果您使用 ADO 作为接口,则 MS 推荐的压缩库将是 JRO。在 Access 中,JRO 不适合紧凑型,因为您已经有可用的 CompactDatabase 方法,即使您没有 DAO 引用(无论您是否有 DAO 引用,DBEngine 在 Access 中始终可用)。换句话说,DBEngine.CompactDatabase 可以在没有 DAO 或 ADO 引用的情况下在 Access 中使用,而 JRO CompactDatabase 方法仅适用于 JRO 引用(或使用后期绑定)。在 Access 之外,JRO 可能是合适的库。

让我强调备份的重要性。您不会需要 1000 次中的 999 次(甚至更少),但是当您需要它时,您会非常需要它!所以千万不要在没有事先备份的情况下进行压缩。

最后,在任何压缩之后,检查压缩文件以查看是否存在名为 MSysCompactErrors 的系统表是个好主意。此表将列出在契约期间遇到的任何问题(如果有的话)。

这就是我现在能想到的关于紧凑型的全部内容。

【讨论】:

不错的帖子,尽管您的回答感觉就像用火箭筒杀死苍蝇。 :) 嘿,是的,我猜。但是这个问题经常被问到,很明显人们在使用数据库,包括 Jet/ACE,却没有对它们的工作原理有基本的了解。这只是将所有内容或多或少地集中在一个地方,并且我希望人们可以在需要时指出它,而不是其他人不得不零碎地回答有关该主题的问题。我喜欢写这样的答案,因为它可以帮助我理解我做什么和不知道什么。我希望它有时也对其他人有所帮助。【参考方案2】:

打开 mdb 并执行“压缩和修复”。这将减小 mdb 的大小。

您还可以将“关闭时压缩”选项设置为开启(默认关闭)。

这里是一些附加信息的链接: http://www.trcb.com/computers-and-technology/data-recovery/ways-to-compact-and-repair-an-access-database-27384.htm

【讨论】:

你是怎么理解的...? 10 年前我也遇到过同样的问题……我想那是我的原话……;-) 您拥有哪个版本的 Microsoft Access? 不建议设置“Compact On Close”,因为它偶尔会出现问题并丢失数据。【参考方案3】:

Microsoft Access 数据库引擎提供了一种 CompactDatabase 方法,可以制作数据库文件的压缩副本。调用 CompactDatabase 之前必须关闭数据库文件。

文档:

Pages on microsoft.com about "Compact and Repair Database" DBEngine.CompactDatabase Method (DAO)

这是一个使用 DAO 复制和压缩 MDB 文件的 Python 脚本:

import os.path
import sys
import win32com.client

# Access 97: DAO.DBEngine.35
# Access 2000/2003: DAO.DBEngine.36
# Access 2007: DAO.DBEngine.120
daoEngine = win32com.client.Dispatch('DAO.DBEngine.36')

if len(sys.argv) != 3:
    print("Uses Microsoft DAO to copy the database file and compact it.")
    print("Usage: %s DB_FILE FILE_TO_WRITE" % os.path.basename(sys.argv[0]))
    sys.exit(2)

(src_db_path, dest_db_path) = sys.argv[1:]
print('Using database "%s", compacting to "%s"' % (src_db_path, dest_db_path))
daoEngine.CompactDatabase(src_db_path, dest_db_path)
print("Done")

【讨论】:

【参考方案4】:

使用 python,您可以使用 pypyodbc 库(.mdb 或 .accdb)进行压缩

import pypyodbc
pypyodbc.win_compact_mdb('C:\\data\\database.accdb','C:\\data\\compacted.accdb')

(source)

然后你可以用shutil将compacted.accdb复制回database.accdb:

import shutil
shutil.copy2('C:\\data\\compacted.accdb','C:\\data\\database.accdb')

(source)

注意:据我所知,对于带有 ODBC 的 Access DB,python 及其库必须是 32 位 (link)。此外,这些步骤可能仅适用于 Windows 操作系统。

【讨论】:

以上是关于如何压缩 MS Access 数据库的主要内容,如果未能解决你的问题,请参考以下文章

单击“压缩和修复数据库”后,如何阻止 vba 编辑器中的 MS 访问断点消失?

ms access 2003 .mdb 无法查看表

为啥我应该关心压缩 MS Access .mdb 文件?

MS Access Jet 数据库以编程方式紧凑

如何强制 MS Access 保留其 SQL 格式?

添加背景图像时MS Access表单大小增加[重复]