当前位置: 首页 > 面试题库 >

将pg_try_advisory_xact_lock()放在嵌套的子查询中?

郎泰平
2023-03-14
问题内容

在我的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"
)

但是在这里Postgrespg_try_advisory_lock阻止了所有记录他们说,如果我没记错的话,我不
应该pg_try_advisory_lock()WHERE子句中使用,因为我将在被扫描的整个集合中的 每一行 调用 一次
(作为过滤的一部分)出现在where子句中)。

我只希望查询在其中找到并更新第一行(随机地LIMIT),available = true并将其更新为available = false,并且我需要在执行此操作时锁定该行,但无需发出新请求来等待先前锁的释放,因此我添加了像这里建议的咨询锁。

我应该放在条款pg_try_advisory_lock()之外WHERE吗?怎么做?


问题答案:

我更新了参考答案,并提供了更多解释和链接。
在Postgres 9.5(目前为beta)中,新功能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;
  • 所有的双引号都带有合法的小写字母名称。
  • 由于career_available是一个布尔列,因此您可以简化opportunity_available = trueopportunity_available
  • 您不需要*从子查询返回,就id足够了。

通常,它 按原样 工作。解释如下。

避免对不相关的行进行咨询性锁定

可以肯定的是, 应用到下一个查询级别 之前 ,您可以将所有谓词封装在带有OFFSET 0黑客的CTE或子查询中(减少开销):
__pg_try_advisory_xact_lock()

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以验证Postgres实际使用该索引。这样,pg_try_advisory_xact_lock(id)将成为索引或位图索引扫描的筛选条件,并且仅将对合格行进行测试(并锁定),因此您可以使用简单的表单而无需其他嵌套。同时,您的查询性能得到了优化。我会做

即使 几个不相关的行 _ 偶尔_
会获得咨询锁,通常也没关系。咨询锁仅与实际使用咨询锁的查询有关。还是您真的有其他并发事务也使用咨询锁并定位同一表的其他行?真的吗?

唯一有问题的情况是,如果大量不相关的行获得了咨询锁,那么只有在顺序扫描时才会发生这种情况,即使在那时也不太可能。



 类似资料:
  • 问题内容: 我想使用ES进行图书搜索。因此,我决定将作者姓名和标题(作为嵌套文档)放入索引,如下所示: 我不明白的是:如何构造搜索查询,以便在搜索“一二”时仅找到第二本书,而在搜索“二三”时什么也找不到,而在搜索“一”时所有图书呢? 问题答案: 也许是这样的? 该查询基本上说一个文件必须有and 。您可以轻松地重新配置该查询。例如,如果您只想搜索作者,请删除嵌套部分。如果您想要另一本书,请更改嵌套

  • 问题内容: 我在获取与Elasticsearch一起使用的嵌套查询时遇到问题(如果我删除了查询字符串之一,则可以使用)。我要解决的问题是我有一个包含关闭列表的文档(关闭)。我想在条件满足另一个值的闭包列表中搜索一个值。那只是从argan = 1的闭包中获得价值 我正在得到这个错误响应; 我的映射如下所示。 有人知道我在做什么错吗? 问题答案: 您的查询不是有效的查询。您需要使用适当的复合查询将其他

  • 和相应的查询解析器 这里的主要想法只是有一个过滤器,可以看到什么食谱有一些成分,用户会通过应用程序通知。 我使用数据库中的所有食谱获得了“recipe”查询,但我需要一个获取这些食谱的查询,然后使用field comprient进行筛选,例如: 食谱-糖蛋糕,配料:糖、蜂蜜、四个… 配方-天鹅绒蛋糕,配料:糖、香草、... 并且用户通知Sugar,API应该返回这2个食谱,但是如果用户通知Suga

  • 我正试图用jooq编写这个查询 我尝试了几件事,但没有成功。到目前为止,我只得到 如何将num列添加到结果中?感谢您的帮助。

  • 我试图创建一个嵌套查询,它将过滤掉一些带有特定术语的文档。在本例中,我试图过滤掉在user.first中有匹配术语的文档。数据示例: 我的查询没有得到所需的结果,因为它返回给我所有未筛选的记录。我尝试使用: 我希望这里得到与过滤器不匹配的文档。在这种情况下,它应该只返回第二个文档。做这件事的正确方法是什么?

  • 本文向大家介绍详解MySQL子查询(嵌套查询)、联结表、组合查询,包括了详解MySQL子查询(嵌套查询)、联结表、组合查询的使用技巧和注意事项,需要的朋友参考一下 一、子查询 MySQL 4.1版本及以上支持子查询 子查询:嵌套在其他查询中的查询。 子查询的作用: 1、进行过滤: 实例1:检索订购物品TNT2的所有客户的ID = + 一般,在WHERE子句中对于能嵌套的子查询的数目没有限制,不过在