SQLite 优化:同时搜索下限和上限

Posted

技术标签:

【中文标题】SQLite 优化:同时搜索下限和上限【英文标题】:SQLite optimization: simultaneous search for lower and upper bounds 【发布时间】:2020-07-20 18:40:49 【问题描述】:

对于基于 SQLite3 的长期运行算法,我有一个简单但巨大的表,如下定义:

CREATE TABLE T(ID INTEGER PRIMARY KEY, V INTEGER);

算法的内部循环需要在给定某个整数N、小于或等于N的最大ID、与之关联的值V以及最小的情况下找到ID 严格大于 N

以下一对请求确实有效:

SELECT ID, V FROM T WHERE ID <= ? ORDER BY ID DESC LIMIT 1;
SELECT ID FROM T WHERE ID > ? LIMIT 1;

但我觉得应该可以将这两个请求合并为一个请求。当 SQLite 查询主索引发现 ID 刚好小于 N(第一个请求)时,B 树索引中的下一个条目已经是第二个请求的答案。

给出一个数量级,表T有超过10亿行,内部请求需要执行超过1000亿次。因此,每一微秒都很重要。当然,我会在具有大量 RAM 的服务器上使用快速 SSD。如果 PostgreSQL 在不占用更多磁盘空间的情况下使用起来更快,那么它也是一种选择。

【问题讨论】:

第二个查询不是缺少ORDER BY ID 吗?否则无法保证所选 id 是可能的最小值 @bwt 理论上可以,但是SQLite默认总是按照主键的顺序枚举,所以排序没有效果。 【参考方案1】:

这是对我自己问题的回答。虽然我还没有找到问题中发布的更好的 SQL 请求,但我做了一些初步的速度测量,稍微改变了视角。以下是我的观察:

    根据ID 值是顺序还是随机顺序,搜索或插入性能存在很大差异。在我的应用程序中,ID大部分是连续的,但也有很多例外。 执行这对 SQL 请求所花费的时间少于单独执行的每个请求的总和。这在随机顺序中最为明显。这意味着当第二个 SQL 请求运行时,访问下一个 ID 的 B-Tree 始终在缓存内存中,第二次遍历索引会更快。 每个请求的搜索和插入时间随着行数的增加而增加。在顺序上,差异很小,但在随机顺序中,增加是可观的。索引 B-Tree 本质上是 O(log N),此外,随着文件大小的增加,操作系统缓存的性能会降低。

这是我在配备 SSD 的快速服务器上的测量结果:

        | Insertion (µs)| Search (µs)
# rows  | sequ.  random | sequ.  random
10^5    | 0.60    0.9   |  1.1    1.3
10^6    | 0.64    3.1   |  1.2    2.5       
10^7    | 0.66    4.3   |  1.2    3.0
10^8    | 0.70    5.6   |  1.3    4.2
10^9    | 0.73          |  1.3    4.6

我的结论是,SQLite 内部逻辑似乎不是可预见算法的瓶颈。大型表的瓶颈是磁盘访问,即使在快速 SSD 上也是如此。我不希望使用另一个数据库引擎有更好的性能,也不希望使用定制的 B-Tree。

【讨论】:

以上是关于SQLite 优化:同时搜索下限和上限的主要内容,如果未能解决你的问题,请参考以下文章

如何在R中找到函数的上限和下限

搜索 sqlite 数据库的最佳方法

我如何向 Google ortools 添加一组值而不是下限和上限?

sqlite性能优化

怎么区别java泛型的上限和下限??

如何在 sqlite 中创建物化视图?