这可能是新手痴迷于优化那些应该不去管的东西,但我一直在努力解决在应用程序代码中执行多少工作以及在 SQLite 查询中执行多少工作。我尝试尽可能多地进行查询,认为 SQLite C 代码将比我更好地处理它。现在,我有大量查询存储在命名空间中,并且一些查询与大量
:varName
类型替换内联;而且,尽管到目前为止一切似乎都工作正常,但随着代码的增长,我想知道我是否正确处理了这个问题。
当 Tcl 第一次读取脚本并将其中至少一部分转换为字节代码时,在 SQLite
db eval
语句中包含查询文本与将查询存储在命名空间变量中之间有什么区别,特别是当它们包含 :varName
类型时替换并且 $::SQL::queryName
字符串永远不会改变?例如,
proc DoSomethingChallenging {} {
lassign [db eval $::SQL::sortOfLongQuery] a b c
lassign [db eval {
with recursive ...
...
where data_key <> :endKey
}] a b c
}
解释器是否可能无法执行某些优化,因为它必须将
$::SQL::sortOfLongQuery
视为可能在过程调用之间发生变化的东西?
同样,我有大约十个过程集,每个过程以几乎相同的方式更新数据库表,除了查询顺序和变量计算方式之外。换句话说,查询是相同的,但
:varNames
不同。到目前为止,我已将查询保留在每个过程中的 db eval {}
语句中,因为尝试更改变量名称以使其在所有过程中保持一致会相当混乱;但可以在运行查询之前将它们分配给新的变量名称,以便可以用 $::SQL::queryName
替换文本;或者这些变量名称可以传递到另一个过程,该过程将它们读取为一致的名称并从该上下文运行查询。
除了减少每个过程中的代码行数之外,尝试这样做还有什么价值吗? SQLite 的预准备语句缓存可能会更小,因为查询字符串将是相同的,因为
:varNames
在过程调用之间是一致的。但是添加额外的变量名或过程只是为了以不同的方式调用查询会导致 Tcl 不必要的额外工作吗?
感谢您考虑我的问题。
在这种情况下本质上没有什么区别;尽管有缓存,但它完全在扩展内。 (SQL 文本充当缓存的关键以及被编译的内容;这不是 Tcl 实现可以缓存内容的唯一方式,但它是这里的相关方式。)然而,它主要被认为是尽可能将 SQL 作为直接文字的良好风格,有几个原因:
查找一个变量的成本通常比执行真正复杂的 SQL 的成本要低很多,尤其是最终必须执行 I/O 的任何操作。 (成本与内存数据库更加相似。) 如果您愿意,可以使用
time
命令验证我关于性能的断言。