我正在使用SQLite3来存储大约1 000 000个节点的 5D常规网格,并且在“SELECT”查询的性能方面存在一些问题。
每个条目由5 + 25个双精度组成,代表常规网格(节点)上的一个点:
每个点都是唯一的(5个第一个值的任何组合都是唯一的)。
该表是使用CREATE TABLE myTable(v1 double,..., v5 double, p1 double,..., p25 double)
创建的。我没有添加任何具体约束。
条目按其坐标后的升序排序(v1,然后是v2,然后是v3,......):
v1|v2|v3|v4|v5|p1|p2|p3|...
0| 0| 0| 0| 0| x| x| x|...
0| 0| 0| 0| 1| x| x| x|...
0| 0| 0| 0| 2| x| x| x|...
...
0| 0| 0| 1| 0| x| x| x|...
0| 0| 0| 1| 1| x| x| x|...
0| 0| 0| 1| 2| x| x| x|...
...
我使用CREATE INDEX idx ON myTable (v1,v2,v3,v4,v5)
我想在5D网格中进行“立方”插值。所以我必须围绕我想要的点在每个维度中提取4个点。我的SELECT查询应返回4 * 4 * 4 * 4 * 4 = 1024点。
由于symetric属性,我必须进行16次查询而不是1.每个请求的格式为SELECT * FROM myTable WHERE (v1=X AND v2=X AND v3 BETWEEN x1 AND x2 AND v4 BETWEEN y1 AND y2 AND v5 BETWEEN z1 AND z2)
。
实际上,v1和v2是角度。在我的5D网格中,我的值为-165到180,步长为15°。因此,如果我想在-160处插值,我无法查询类型v1 BETWEEN -180 AND -135
(得到-180,-165,-150,-135),因为-180不存在于我的桌子。我可以优化这部分只做4个查询,但这不是我的主要关注点。
我正在使用一份准备好的声明:
sqlite3_prepare_v2(db,"SELECT * FROM myTable WHERE (v1=? AND v2=? AND v3 BETWEEN ? AND ? AND v4 BETWEEN ? AND ? AND v5 BETWEEN ? AND ?"),length,statement,NULL)
然后,对于每个查询,我这样做:
sqlite3_bind_double(statement, int, double);
while(sqlite3_step(statement)==SQLITE_ROW) {
// for each row (for each "node") :
// 1) retrieve its properties
double myvar1 = sqlite3_colum_double(statement,6)
double myvar2 = sqlite3_colum_double(statement,7)
....
double myvar25 = sqlite3_colum_double(statement,25)
// 2) create the object and add it to a vector for the interpolation
}
sqlite3_reset(statement);
sqlite3_clear_bindings(statement);
打开数据库
sqlite3_open_v2(path,&db,SQLITE_OPEN_READONLY,NULL)
进行16次查询并提取1024点需要大约2.5秒。 Sqlite3操作需要99.8%的计算工作量(callgrind)......
我做错了什么?
我试过了EXPLAIN QUERY PLAN SELECT * FROM myTable WHERE (v1=0 AND v2=0 AND v3 BETWEEN 0 AND 3 AND v4 BETWEEN 0 AND 3 AND v5 BETWEEN 0 AND 3
。
结果是SEARCH TABLE myTable USING INDEX idx (v1=? AND v2=? AND v3>? AND v3<?)
基于5坐标创建唯一索引并进行1024次查询会更快吗?之前,我使用了矢量并通过索引直接访问。
答案 0 :(得分:0)
使用相等比较(=
)进行查找时,正常索引效果最佳。
正如您在EXPLAIN QUERY PLAN输出中看到的那样,非相等比较会阻止使用索引的任何其他列;数据库必须扫描所有可能的v4
和v5
行以查找结果。
您在常规网格中查询相当少的点,因此您可以准确了解所需点的坐标。 只需使用一个简单的查询来搜索具有所有五个精确坐标的点,并执行1024次。 这将导致单个索引查找效率更高,即使它是针对每个点执行的。
为了使多个查询更有效,请将所有查询包装在一个事务中。
使用单独的R-tree索引查找积分。 R树针对(多维)间隔查询进行了优化。 这将导致如下查询:
SELECT *
FROM myTable
WHERE rowid IN (SELECT id
FROM RtreeIndexTable
WHERE v1 = ?
AND v2 = ?
AND v3 BETWEEN ? AND ?
AND v4 BETWEEN ? AND ?
AND v5 BETWEEN ? AND ?)
R树通常用于不规则或稀疏数据;如果你可以通过查询单个点来逃避,那么R树可能会有点过分。