比较 SQLite 的 PRAGMA quick_check 与 integrity_check — 通过读取检查数据库异常

プログラミング・Web開発カテゴリを表すパンダのイラスト 编程・Web开发

关于本文
本文是通过利用生成式 AI 的自动化生成流程创建的。本文参考了 SQLite 官方的 PRAGMA 规范,并通过安全的内存数据库示例解释 quick_check、integrity_check 和 foreign_key_check 的区别。示例尚未在真实设备上运行验证。

验证状态:📘 已确认 SQLite 官方文档 / 实际设备未验证

为了确认 SQLite 数据库是否正常,有时会使用PRAGMA integrity_check。输出结果如果是ok就万无一失了吗?答案是“作为结构检查,这是一个好结果,但并不能保证包含外键的业务数据的正确性”。

SQLite 中有quick_check和integrity_check,以及另一个foreign_key_check。本文将故意制造包含外键违规的数据,并对比这三者的区别。

三种检查

功能主要检查对象注意事项
PRAGMA quick_check低级别简易检查部分省略 UNIQUE 与索引/表的一致性等
PRAGMA integrity_check详细的底层完整性与约束不包含外部键违规
PRAGMA foreign_key_check没有引用目标的子记录并不涵盖文件损坏

SQLite 的PRAGMA 官方文档中说明,integrity_check 无法检测外部键违规,必须使用 foreign_key_check。

在不破坏任何内容的前提下进行尝试

以下代码不使用文件,而是准备了一个名为:memory:的易失性数据库。除 Python 标准库中的 sqlite3 之外,不需要其他依赖。您可以直接在不接触现有数据库的情况下进行测试。使用以下命令运行。

import sqlite3

with sqlite3.connect(":memory:") as db:

    # 教材用の接続内だけFK強制をOFFにする

    db.execute("PRAGMA foreign_keys=OFF")
    db.executescript("""
        CREATE TABLE parent (id INTEGER PRIMARY KEY);
        CREATE TABLE child (
            id INTEGER PRIMARY KEY,
            parent_id INTEGER REFERENCES parent(id)
        );
        INSERT INTO parent(id) VALUES (1);
        INSERT INTO child(id, parent_id) VALUES (10, 99);
    """)
    db.commit()
    db.execute("PRAGMA foreign_keys=ON")

    for label, statement in [
        ("quick_check", "PRAGMA quick_check"),
        ("integrity_check", "PRAGMA integrity_check"),
        ("foreign_key_check", "PRAGMA foreign_key_check")
    ]:
        print(label, db.execute(statement).fetchall())

您可以在不触碰现有数据库的情况下进行测试。使用以下命令运行。

python3 check-db.py

完整文件已保存在Daily-Code-Samples:SQLite 检查比较中。

预期输出

quick_check [('ok',)]
integrity_check [('ok',)]
foreign_key_check [('child', 10, 'parent', 0)]

这是执行结果的预期示例,而非实际设备的转录。父表中只有 ID=1,而子表中存在引用不存在的父 ID=99 的记录,因此预计仅在最后的检查中发现违规。

数据库可读、结构完好、数据语义正确是各自独立的条件。

修改一处以查看差异

请更改示例中的这行代码。

-- 変更前
INSERT INTO child(id, parent_id) VALUES (10, 99);

-- 変更後
INSERT INTO child(id, parent_id) VALUES (10, 1);

为了引用存在的父记录,修改后foreign_key_check也应该不会再返回违规错误。可以预期两个结构检查都会ok保持不变。

另一个观察点是PRAGMA foreign_keys=ON的位置。如果在已经开始了事务的情况下进行切换,可能无法按预期送达。这就是为什么此处commit()要明确指出的原因。

为什么要将检查分开

SQLite 的索引与行数据的一致性确认需要文件结构级别的处理。而外键的引用关系则是表内字段之间的关系。

例如,即使订单明细引用了客户主数中不存在的客户 ID,SQLite 文件也不一定已经损坏。即使内部结构检查成功,也不能保证鐀售汇总或账单的一致性。

反之,即使业务数据的引用关系看起来正常,也不能保证磁盘没有故障。关键是不要混淆职能不同的检查。

在生产数据库中需要注意的事项

虽然本演礰中关闭了外键约束的强制性并创建了违规行,但是请不要在业务数据库中模仿这种做法。为了诊断现有的数据库,没有必要禁用约束。

当针对实际的数据库进行操作时,应先考虑数据量对应的检查时间、备份、WAL 模式、其他进程的并发更新以及权限。即使是读取操作,也可肽产生磁盘 I/O 和锁的负载。

即使检查出错误,也不要在未查明原因的情况下删除文件或执行 REINDEX,而应先保护备份并考察原因。

运绶中的用法区分

  • 日常轻量观测:可选用 quick_check。但需理解其省略的检查项。

  • 唉疑存在不一致性时:查看 integrity_check 的详细结果。

  • 外键一致性:另外执行 foreign_key_check。

  • 即便如此,这并不意味着“业务值是正确的”,因此需要与应用程序的检查进行核对。

官方信息

文档信息

文章??
比较 SQLite 的 PRAGMA quick_check 与 integrity_check — 通过读取检查数据库异常
?布日期
更新日期
来源
https://papanda925.com/?p=18089&lang=zh

?可: ?于本站?有相??利的正文及原??表,除非?有?明,可依据 CC BY 4.0 使用。本文可能包含使用生成式AI?建或??的内容。若代??有?可声明,或?接的GitHub???定了?可,?代?以??可?准。引用内容、第三方?料、?片及商?不在本?可范?内。 使用政策

标题和URL已复制