在5个双字段上使用SELECT查询的SQLite3 c ++性能问题

时间:2014-07-28 17:32:04

标签: c++ sql database-design sqlite database-performance

我正在使用SQLite3来存储大约1 000 000个节点的 5D常规网格,并且在“SELECT”查询的性能方面存在一些问题。

上下文

数据库描述

每个条目由5 + 25个双精度组成,代表常规网格(节点)上的一个点:

  • 5个第一双:5D规则网格上的点坐标(v1,v2,...,v5)
  • 25次以下双打:一些特征(p1,p2,...,p25)

每个点都是唯一的(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)

在此表上创建了一个INDEX

SELECT查询描述

我想在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次查询会更快吗?之前,我使用了矢量并通过索引直接访问。

1 个答案:

答案 0 :(得分:0)

使用相等比较(=)进行查找时,正常索引效果最佳。 正如您在EXPLAIN QUERY PLAN输出中看到的那样,非相等比较会阻止使用索引的任何其他列;数据库必须扫描所有可能的v4v5行以查找结果。

  1. 您在常规网格中查询相当少的点,因此您可以准确了解所需点的坐标。 只需使用一个简单的查询来搜索具有所有五个精确坐标的点,并执行1024次。 这将导致单个索引查找效率更高,即使它是针对每个点执行的。

    为了使多个查询更有效,请将所有查询包装在一个事务中。

  2. 使用单独的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树可能会有点过分。