“如果可以在一条 sql 语句中使用 sqlite”:
是的,这是可能的。 “UPSERT”声明已在此 question 中进行了很好的讨论。
应用于您的扩展案例,您可以在一个语句中这样做:
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 进行的小性能基准测试,对 table info 中 5000 行的基本数据集运行 100.000 次修改,50% 更新,50% 插入,证实了上述结论:
- 使用三个准备好的语句(首先是选择,然后是更新或插入,具体取决于所选数据):702ms
- 使用上面的组合语句:1802ms
运行时在多次运行中相当稳定。