我对执行Postgres函数有一些常规查询。我最近注意到,如果我将任何算术或业务操作的输出存储在变量中,然后在查询中执行时调用它,而不是在时间执行操作执行它节省了很多时间。
但是我并不知道在Postgres的新手中,通常会采取任何措施来缩短所花费的时间并提高性能。
答案 0 :(得分:2)
注意读 - 修改 - 写周期和事务异常。
只要您仔细考虑缓存它的范围和缓存失效,就可以在本地缓存值。在您阅读它的交易的生命周期内存储值时要非常小心。
除非SELECT ... FOR UPDATE
在写入期间保持打开的事务中的值SERIALIZABLE
,否则还必须小心不要将该缓存值用作写回数据库的计算的输入,使用{ {1}}交易,或您使用某种形式的optimistic concurrency control。
如果你不小心你可以让自己陷入困境,经典就像银行并发例子,其中账户id = 1将$ 100转移到账户id = 2和id = 3:
session1 session2
begin; begin;
select balance
from account
where id=1; => 100
select balance
from account
where id = 1; => 100
update account
set balance = balance + 100
where id = 2; -- this is safe
update account
set balance = balance + 100
where id = 3; -- this is safe
update account
set balance = 0 -- 100 - 100 = 0
where id = 1;
update account
set balance = 0 -- 100 - 100 = 0
where id = 1;
commit;
commit;
糟糕!你刚刚为两个人的帐户增加了100美元,但只花了100美元的id = 1。针对id = 2和id = 3的更新是正常的,因为它们对余额(balance = balance + 100
)进行了就地修改。对id = 1的更新不是,因为它们读取了值,修改了它的客户端,并写了一个新的值。
这就是我所说的读 - 修改 - 写周期。
如果我们在阅读余额时使用SELECT ... FOR UPDATE
,那将是安全的,因为第二次交易将一直停留到第一次交易。但如果我们避免了读取 - 写入 - 写入周期并且就地完成了更新,那将会更好。
缓存很好 - 但是当基础数据更新但是你的缓存没有被刷新和刷新时会引入异常。
缓存失效通常是一个难题,但Pg有一些帮助的工具。
特别是,从触发器调用的listen
和notify
可用于通过助手守护程序急切地从存储在memcached / redis /中的缓存中刷新数据。这意味着你不太可能必须刷新大块缓存,或者在发生变化时丢弃整个缓存。
您还需要决定过时的事情是否过时。有时你只是不在乎过时5秒的值。还是半个小时。或一周。这取决于应用程序,相关数据等。
答案 1 :(得分:0)
将值存储在变量中没有什么特别的错误。
如果您正在存储值,那么您可以按程序,逐步的方式而不是面向集合的方式编写SQL,那么您最好不要这样做。 SQL是一种面向集合的语言;如果你编写面向集合的SQL,它通常会表现得更好。
存储值并在以后使用它们的风险是,自存储它们以来,这些值的基础数据可能已经发生了变化。这是一个真正的问题是特定于应用程序,但通常 是一个最好避免的问题。