将pg_try_advisory_xact_lock()放在嵌套的子查询中?
在我的Ruby on Rails 4应用程序中,我对Postgres 9.4数据库进行了此查询:
@chosen_opportunity = Opportunity.find_by_sql( " UPDATE \"opportunities\" s SET opportunity_available = false FROM ( SELECT \"opportunities\".* FROM \"opportunities\" WHERE ( deal_id = #{@deal.id} AND opportunity_available = true AND pg_try_advisory_xact_lock(id) ) LIMIT 1 FOR UPDATE ) sub WHERE s.id = sub.id RETURNING sub.prize_id, sub.id" )
非常受dba.SE相关答案的启发 。
但是这里( Postgres pg_try_advisory_lock会阻止所有记录 )他们说,如果我没弄错的话,我不应该在WHERE
子句中使用pg_try_advisory_lock()
,因为我会在扫描的整个集合中每行调用一次 (作为一部分) where子句中发生的过滤)
我只是希望我的查询找到并更新第一个(随机,带LIMIT
)行,其中available = true
并将其更新为available = false
,我需要在执行此操作时锁定该行,但不要让新请求等待发布之前的锁,所以我添加了像这里建议的咨询锁。
我应该在WHERE
子句之外放置pg_try_advisory_lock()
吗? 怎么做?
我用更多的解释和链接更新了我的参考答案。
在Postgres 9.5(目前测试版)中,新的SKIP LOCKED
是一个卓越的解决方案:
- Postgres UPDATE … LIMIT 1
让我先简化一下你的查询中的一些事情:
直接查询
UPDATE opportunities s SET opportunity_available = false FROM ( SELECT id FROM opportunities WHERE deal_id = #{@deal.id} AND opportunity_available AND pg_try_advisory_xact_lock(id) LIMIT 1 FOR UPDATE ) sub WHERE s.id = sub.id RETURNING s.prize_id, s.id;
- 所有双引号都只是你的合法,小写名称的噪音。
- 由于opportunity_available是一个布尔列,您可以将
opportunity_available = true
简化为opportunity_available
- 你不需要从子查询返回
*
,只需id
。
通常,这是按原样工作的 。 说明如下。
避免对不相关的行进行咨询锁定
可以肯定的是,在下一个查询级别应用pg_try_advisory_xact_lock()
之前 ,您可以使用OFFSET 0
hack(较少的开销)将所有谓词封装在CTE或子查询中:
UPDATE opportunities s SET opportunity_available = false FROM ( SELECT id FROM ( SELECT id FROM opportunities WHERE deal_id = #{@deal.id} AND opportunity_available AND pg_try_advisory_xact_lock(id) OFFSET 0 ) sub1 WHERE pg_try_advisory_xact_lock(id) LIMIT 1 FOR UPDATE ) sub2 WHERE s.id = sub.id RETURNING s.prize_id, s.id;
但是 ,这通常要贵得多。
你可能不需要这个
如果您的查询基于涵盖所有谓词的索引(例如此部分索引),则不会有任何“附属”咨询锁定:
CREATE INDEX opportunities_deal_id ON opportunities (deal_id) WHERE opportunity_available;
检查EXPLAIN
以validationPostgres实际使用索引。 这样, pg_try_advisory_xact_lock(id)
将成为索引或位图索引扫描的过滤条件,并且仅开始测试(和锁定)合格行,因此您可以使用简单forms而无需额外嵌套。 同时,您的查询性能已得到优化。 我会这样做的。
即使一些不相关的行应该偶尔得到一个咨询锁,这通常也无关紧要。 咨询锁只与实际使用咨询锁的查询相关。 或者你真的有其他并发事务也使用咨询锁并瞄准同一个表的其他行? 真?
唯一的另一个有问题的情况是,如果大量不相关的行获得咨询锁定,这只能通过顺序扫描发生,即便如此也是如此。
- 如何在雪豹上安装gempg
- Ruby Guard问题 – ‘请安装sqlite3适配器’ – railstutorial.org
- Rails:在同一个应用程序中同时使用mysql和postgres?
- 在Heroku上,“PGError:致命:由于管理员命令终止连接”的原因是什么?
- 使用rvm在Mac OS Lion上安装pg gem
- rails postgres insert
- Rails 4 / postgresql – 根据另一个表数据在表上插入数据(after_create)
- Rails用范围扩展字段,PG不喜欢它
- postgresql datababse出错:服务器是否在本地运行并接受Unix域套接字“/var/run/postgresql/.s.PGSQL.5432”上的连接?