我正在实现一个使用sqlite3数据库作为后端的FUSE文件系统。我不打算更改数据库后端,因为我的文件系统使用sqlite3作为文件格式。文件系统必须实现的功能之一是readdir
函数。此功能允许进程通过重复调用目录并获取接下来的几个目录项(与缓冲区可以容纳的目录数相同)来迭代读取目录的内容。返回的目录条目可以以任何顺序返回。我想通过以下查询实现此操作:
SELECT fileno, name FROM dirents WHERE dirno = ? LIMIT -1 OFFSET ?;
其中
dirno
是我正在读取的目录,而OFFSET ?
是我已经返回的条目数。我想读取尽可能多的行以适合缓冲区(我无法预测计数,因为这些是可变长度记录,具体取决于文件名的长度),然后重置查询。由于FUSE的无状态性质,因此不能选择一直打开查询并返回接下来的几行直到目录结束,因为我无法可靠地检测到进程是否过早地关闭了目录。
dirents
表具有以下架构:CREATE TABLE dirents (
dirno INTEGER NOT NULL REFERENCES inodes(inum),
fileno INTEGER NOT NULL REFERENCES inodes(inum),
name TEXT NOT NULL,
PRIMARY KEY (dirno, name)
) WITHOUT ROWID;
题
理论上,
SELECT
语句不按定义顺序产生行。在实践中,我可以假设当我用连续更大的SELECT
值多次执行相同的准备好的OFFSET
语句时,得到的结果与在单个查询中读取所有数据时得到的结果相同,即行顺序为每次相同的未指定顺序?当前的假设是在查询之间不修改数据库。我可以假设当不同的查询修改其间的
dirents
表时,行顺序保持合理地相似吗?程序当然可以观察到一些故障(例如,目录条目出现两次),但是为了可用性(readdir
的主要用户是ls
命令),如果目录列表通常大部分正确,则非常有用。如果我无法做出这些假设,那么什么是达到预期结果的更好方法?
我知道我可以抛出
ORDER BY
子句来使行顺序定义得很好,但是我担心这可能会对性能产生重大影响,尤其是在读取大目录中的小块内容时,必须对目录进行排序每次读取一个块。 最佳答案
解决此问题的正确方法是使用order by
。如果您担心订单的执行情况,请在用于order by
的列上使用索引。
我认为,最简单的方法是删除表创建中的without rowid
选项。然后,您可以按以下方式访问该表:
SELECT fileno, name
FROM dirents
WHERE dirno = ?
ORDER BY rowid
LIMIT -1 OFFSET ?;
我意识到这会为每行添加额外的字节,但这是出于良好的目的-确保您的查询正确。
实际上,此表的最佳索引应在
dirno, rowid, fileno, name
上。给定where
子句,除非有索引,否则您还是要进行全表扫描。