sqlite:插入或更新一行,性能问题

时间:2013-11-22 05:25:26

标签: sqlite

sqlite table:

CREATE TABLE IF NOT EXISTS INFO
(
    uri TEXT PRIMARY KEY,
    cap INTEGER,
    /* some other columns */
    uid TEXT
);

INFO表有5K +行,可在低功耗设备上运行(与3年前的手机相当)。 我有这个任务:在INFO表中插入带有一些值的新URI,但是,如果URI已经存在,那么我需要通过向其添加额外的文本来更新uid文本字段 if < / em>在现有uid字符串中找不到要追加的额外文本;所有其他字段应保持不变。

举个例子:INFO已经uri=http://example.com”与此uid字符串:“| 123 || abc || xxx |”。 我需要添加uri =“http://example.com”和uid =“| abc |”。自“| abc |”是uri的现有字段中的子字符串,则不应更新任何内容。无论如何,不​​应更新剩余的字段

为了完成它,我有以下选择:

  1. 构建一些sql查询(如果可以在一个sql语句中使用sqlite执行类似的操作),
  2. 分两步手动完成所有操作: a)检索uid行,手动执行所有处理, b)更新现有内容或根据需要插入新行
  3. 考虑到这是受约束的设备,哪种方式更可取?如果我省略了子字符串匹配的额外要求并且总是将uid附加到现有的uid字段,该怎么办?

1 个答案:

答案 0 :(得分:1)

“如果在一个sql语句中可以使用sqlite”:

是的,有可能。在这个question中已经很好地讨论了“UPSERT”语句。

适用于您的扩展案例,您可以在一个声明中这样做:

insert or replace into info  (uri, cap, uid) 
values ( 'http://example.com', 
         coalesce((select cap  from info where uri  = 'http://example.com'),'new cap'),
         (select case 
             when (select uid 
                   from  info 
                   where uri  = 'http://example.com') is null 
             then '|abc|'
             when instr( (select uid 
                          from  info 
                          where uri  = 'http://example.com'),'|abc|') = 0 
             then (select uid 
                   from info 
                   where uri  = 'http://example.com') || '|abc|'
             else (select uid 
                  from  info 
                  where uri  = 'http://example.com')
             end )
      );

检查EXPLAIN QUERY PLAN给我们

selectid    order       from        detail
----------  ----------  ----------  -------------------------
0           0           0           EXECUTE SCALAR SUBQUERY 0
0           0           0           SEARCH TABLE info USING INDEX sqlite_autoindex_INFO_1 (uri=?)
0           0           0           EXECUTE SCALAR SUBQUERY 1
1           0           0           EXECUTE SCALAR SUBQUERY 2
2           0           0           SEARCH TABLE info USING INDEX sqlite_autoindex_INFO_1 (uri=?)
1           0           0           EXECUTE SCALAR SUBQUERY 3
3           0           0           SEARCH TABLE info USING INDEX sqlite_autoindex_INFO_1 (uri=?)
1           0           0           EXECUTE SCALAR SUBQUERY 4
4           0           0           SEARCH TABLE info USING INDEX sqlite_autoindex_INFO_1 (uri=?)
1           0           0           EXECUTE SCALAR SUBQUERY 5
5           0           0           SEARCH TABLE info USING INDEX sqlite_autoindex_INFO_1 (uri=?)

据我所知,sqlite不会缓存标量子查询的结果(当查看EXPLAIN为上述语句生成的VM代码时,我找不到任何chaching的证据)。因此,由于sqlite是进程内数据库,因此使用两个单独的语句执行操作很可能比这更好。

您可能希望对此运行时进行基准测试 - 结果当然取决于您的主机语言和您使用的接口(C,JDBC,ODBC,...)。

修改

使用JDBC驱动程序和sqlite 3.7.2进行一点性能基准测试,在表信息中的5000行基本数据集上运行100,000次修改,50%更新,50%插入,确认了上述结论:

  1. 使用三个准备好的陈述(首先是选择,然后是更新或插入,具体取决于所选数据): 702ms
  2. 使用上述合并声明: 1802ms
  3. 运行时间在几次运行中非常稳定。