检测 SQLite 中的全表扫描
摘要
本文展示了如何利用 SQLite 的语句统计 API 检测全表扫描,并建议将其集成到 Rails 中,以便在测试/开发环境中发出警告或报错。
<p><a href="https://lobste.rs/s/eilycs/detecting_full_table_scans_with_sqlite">评论</a></p>
查看缓存全文
缓存时间: 2026/07/16 01:50
# 使用 SQLite 检测全表扫描
来源:https://tenderlovemaking.com/2026/07/15/detecting-full-table-scans-with-sqlite/
本周我正在参加 RubyConf(https://rubyconf.org/),感觉太棒了!
我最近读到 lobste.rs(https://lobste.rs/)现在运行在 SQLite 上(https://lobste.rs/s/ko1ji1/lobste_rs_is_now_running_on_sqlite)。文章中有一部分引起了我的注意:
> 我希望我们能在测试中说:“如果遇到任何全表扫描就失败。” 这样本可以帮我们抓住第一次部署时遇到的性能问题。
SQLite 会收集预编译语句的信息,并通过 API(https://sqlite.org/c3ref/stmt_status.html)暴露这些统计数据。这意味着我们在执行语句后,无需使用 `EXPLAIN` 就能判断该语句是否进行了全表扫描。
下面是一个示例程序,演示如何检测查询是否进行了全表扫描:
```ruby
db = SQLite3::Database.new(":memory:")
db.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)")
# 插入大量记录
1_000.times do |i|
db.execute("INSERT INTO users (name, age) VALUES (?, ?)",
["user#{i}", i % 100])
end
# 准备一个语句并查询
stmt = db.prepare("SELECT * FROM users WHERE age = ?")
stmt.bind_param(1, 42)
stmt.to_a
# 检查全扫描步数,由于查询进行了全表扫描,我们会看到很多步
fullscan_steps = stmt.stat(:fullscan_steps)
puts "fullscan_steps: #{fullscan_steps}"
if fullscan_steps > 0
puts "=> 查询进行了全表扫描"
end
# 创建索引
db.execute("CREATE INDEX idx_users_age ON users(age)")
# 现在查询不再进行全表扫描
stmt2 = db.prepare("SELECT * FROM users WHERE age = ?")
stmt2.bind_param(1, 42)
stmt2.to_a
puts "添加索引后,fullscan_steps: #{stmt2.stat(:fullscan_steps)}"
```
感觉我们可以将其集成到 Rails 中,在测试或开发模式下发出警告或直接异常。我不确定是否要在生产环境中始终检查这一点,但也许也没问题?
相似文章
用细齿梳检查 SQLite
John Regehr 描述了使用 tis-interpreter 在 SQLite 中搜索未定义行为,发现了其他工具遗漏的错误,如悬空指针使用和未初始化读取。
在SQLite中推荐使用严格表
SQLite的严格表强制执行严格类型检查,以防止常见的数据类型错误。本文介绍了如何使用它们以及它们的优缺点。
@eladgil: https://x.com/eladgil/status/2079561730263531771
Cursor 团队的 AI 代理根据手册将 SQLite 重构成 Rust 代码,并成功通过所有测试,成本因模型组合不同而相差 15 倍。
我用于检测交易欺诈的SQL模式
一份实用指南,介绍六种用于检测金融数据中交易欺诈的SQL模式,包括速度检查、不可能旅行检测等方法。作者分享了真实案例和调优建议。
SQLite 查询解释器
一个基于浏览器的工具,可对 SQLite 运行 SQL 查询,并以通俗易懂的英文解释查询计划和字节码输出。