我试图理解我可能做错了什么,或者不理解在Tcl中使用用户定义函数时不使用-deterministic标志;以及对于相同输入缓存其结果的“生存期”。
例如,我将这个简单的查询改为用户自定义函数;而且,忘记了-deterministic标志的重要性,花了大量的时间试图弄清楚为什么get_key()总是为7时,表doc_pointers中的每一行都被调用。
select *
from
doc_pointers
--where key = order_keys->>:startIdx -- 7
where key = get_key('a',:startIdx); -- 7
我的意思是“总是”只在select
语句的“生命周期”中,因为CTE中的另一个查询(这是它的一部分)可能会更改键的顺序,并且:startIdx可能不再返回7。当然,json_array方法也是如此;而且它似乎不会对doc_pointers中的每一行都重新调用。
此外,在递归查询的这一段中,非递归部分为表doc_pointers的每一行调用get_key('a',18)
;但是在递归部分中,不是对每一行都调用get_key('b', p.order_idx + :loopDir)
。
我知道这一点,因为我每次调用get_key()都打印到stdout,并且可以看到doc_pointers中的每一行都有一个“a”行,只有少量的“b”行是预期的。我期待一个'a'行,这是当where
子句是r.key = 7
时发生的情况。
我可以将get_key('a',18)
设置为变量,如:startKey,因为它只使用一次,但不能为get_key('b', p.order_idx + :loopDir)
设置,因为它依赖于循环索引。
因此,问题是,1)确定性标志将无限期地缓存:startIdx为7多久?以及2)在这种情况下使用-deterministic标志“安全”吗?3)为什么递归查询的两个部分对待get_key()的方式不同。
我应该补充的是,我尝试使用-deterministic标志进行实验,似乎值的缓存不会持续到当前语句之后,但我想听听知道的人的意见。
谢谢
pieces( order_idx, key, buffer_id, char_start, char_length, char_begin ) as
(
select
18,
r.key,
r.buffer_id,
r.char_start,
r.char_length,
598
from
doc_pointers r
where
r.key = get_key('a',18)
UNION ALL
select
order_idx + :loopDir,
r.key,
r.buffer_id,
r.char_start,
r.char_length,
p.char_begin +
iif(:loopDir > 0, p.char_length, -r.char_length)
from
doc_pointers r,
pieces p
where
r.key = get_key('b', p.order_idx + :loopDir)
and (
(
:loopDir > 0
and p.char_length + p.char_begin <= cast(:breakPt as integer)
)
or
( :loopDir < 0
and p.char_begin >= cast(:breakPt as integer)
)
)
)
1条答案
按热度按时间yv5phkfx1#
-deterministic标志缓存一组特定参数值的函数结果。它不缓存每个参数是如何获得其值的。使用固定值、变量或更复杂的表达式调用函数对缓存没有任何影响。
因此,您应该只在每次对相同输入产生相同结果的函数上使用-deterministic标志。如果函数产生的结果仅取决于提供的参数,则为真。如果函数使用可能更改的附加信息,则它不是确定性的。
澄清一下:你不应该担心如何调用函数。这是使用固定参数还是可变参数无关紧要。您也不需要关心结果缓存多长时间。这只是一种优化。如果条目从该高速缓存中被刷新,sqlite将在下次需要该值时再次调用该函数。如果函数是真正确定性的,则新计算的值将与从该高速缓存中丢失的值完全相同。
缓存结果的时间长短可能取决于不可预测的因素,如可用内存和调用之间缓存的其他函数。试图在您的函数中考虑到这一点实际上是不可行的。
具体来说:当$startIdx = 18并且
get_key('a', :startIdx)
返回7时,缓存的内容是:get_key('a',18)= 7.如果接下来将$startIdx更改为23并再次调用
get_key('a', :startIdx)
,则该函数将再次被调用,因为参数与缓存的结果不匹配。但是,如果调用
get_key('a', 18)
,则将使用缓存的结果。即使你这次使用了一个固定的变量,而不是一个变量。