SQLite 做了太多的小尺寸磁盘读取

Posted

技术标签:

【中文标题】SQLite 做了太多的小尺寸磁盘读取【英文标题】:SQLite doing too many small size disk reads 【发布时间】:2018-09-09 09:22:39 【问题描述】:

背景 我正在使用 SQLite 存储大约 10M 条目,其中每个条目的大小约为 1Kb。我正在使用多个并行线程一次读取大约 100K 个条目的数据块。读取和写入不会并行进行,所有写入都在开始读取之前完成。

问题我遇到了太多磁盘读取。每秒大约发生 3k 次读取,而我在这 3k 次读取中仅读取 30Kb 数据(因此每个磁盘读取大约 100 个字节)。结果,我看到了非常糟糕的性能(读取数据大约需要 30 分钟)

问题

    是否有任何 SQlite 设置/pragma 可以用来避免小尺寸磁盘读取? 在 SQlite 中是否有任何用于批量并行读取的最佳实践? SQlite 是否一次读取所有查询结果?还是以较小的块读取结果?如果是后者,那么它在哪里部分退出查询

实现细节 我在 Java 中使用 SQlite,我的应用程序在 linux 上运行。 JDBC 库是https://github.com/xerial/sqlite-jdbc(版本 3.20.1)。

P.S我已经建立了必要的索引并验证没有进行表扫描(使用解释查询计划器)

【问题讨论】:

【参考方案1】:

当你用索引搜索数据时,数据库首先在索引中查找值,然后到对应的表行读取所有其他列。

除非表中的行碰巧以与索引中的值相同的顺序存储,否则每个这样的表读取都必须转到不同的页面。

仅当搜索减少行数时,索引才会加快搜索速度。如果您要读取所有(或大部分)行,那么表扫描会快得多。

只有当磁盘可以实际处理额外的 I/O 时,并行读取才会更有效率。在旋转磁盘上,额外的寻道只会让事情变得更糟。

(SQLite 试图避免存储临时结果。在您单步通过游标时,结果行是动态计算的(尽可能多地)。)

【讨论】:

谢谢,CL。回复。你说的很有道理,我可以做一些删除索引的实验。我想按排序顺序阅读结果。我正在以分页方式阅读结果sqlite.org/cvstrac/wiki?p=ScrollingCursor。有没有一种模式可以用来在 DB/OS 页面上存储相关结果? 那么你必须按排序顺序插入行。

以上是关于SQLite 做了太多的小尺寸磁盘读取的主要内容,如果未能解决你的问题,请参考以下文章

Sqlite3写性能优化-每秒百万条写入

默然回首繁忙而充实的2016

(sqlite,Flask + React),flask session session.get() 返回 None [重复]

换个角度聊聊Netty

Django admin 和 SQLite:数据库磁盘映像格式错误

为啥我的 HSQLDB 表在磁盘上占用了太多空间?