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 优化:同时搜索下限和上限的主要内容,如果未能解决你的问题,请参考以下文章