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

postgresql 9.4-阻止应用始终选择最新更新的行

林弘壮
2023-03-14
问题内容

我有一个(Ruby on Rails 4)应用程序,并使用了一个PostgreSQL查询,该查询基本上查看机会表,在机会为’available =true’的行中随机搜索,并用’available = false’更新这些选定的行。每次用户单击“尝试机会”时,应用程序都会使用以下查询。

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;
// inspired by https://stackoverflow.com/questions/33128531/put-pg-try-advisory-xact-lock-in-a-nested-subquery

我已经苦苦挣扎了5天,但现在我已经设法大致了解了它的表现(严重):现在我需要知道如何对其进行更改。

实际上,该应用程序“变得有点疯狂”,并完全按照我更新的最新版本进行选择(并更新该行)。

让我清楚我如何创造这些机会的过程

  • 我以管理员身份通过我的应用创建了20个机会(行)

  • 然后在管理面板中创建一个奖品,奖品的数量,比如说奖品id = 45,数量=4。该应用程序将进入“机会”表,并随机填充(这部分工作正常),其中有4行有priest_id = 45。

现在,用户运行该应用程序,并且如上所述,该应用程序将不会随机选择一行,而是始终以最新的更新开始:似乎需要一行中有一个奖品,然后是另一个中有奖品,然后又是另一个,从不那些没有奖品的人(primed_id
=空)…

现在,我进行了一些手动实验:我尝试手动更改表上的值(通过pgadmin),这是最奇怪的事情:如果我修改了第32行,然后是第45行,然后是第67行,当用户再次尝试播放时,猜测一下,则随机选择的行正是我按照相反顺序更新的行:它将依次选择第67行,第45行和第32行。
= true)。

我也尝试不用于更新或’pg_try_advisory_xact_lock(id)’行,看来它仍然有相同的问题。

作为管理员,我首先创建总共20行,然后创建4个获胜行,它们是最后要删除的行(即使在我的pgadmin屏幕上它们仍然位于同一行…也许在背景中,postgresql是将它们作为最后一次连续更新并选择它们吗?),这就是为什么一旦从这4个获胜行中选择了一个,然后所有其他行都跟随着的原因。

需要明确的是,我会逐行选择每个可用的机会(例如:按照我在pgadmin上看到的,第3行,然后第4行,然后第5行,因为行已经完全随机地分配了奖金)。问题是它没有这样做,而是经常连续接获所有获奖行…。

我无语,也不知道如何打破这种模式。

注意:这种模式并不是100%的时间连续发生,而是经常发生:例如,如果我有4个以上的获胜行,那么如果我持续按用户单击2分钟,它就会像此处所说的那样运行,然后停止并似乎(或者我可能是错的)表现正常,然后&分钟之后再次只会选择获胜的行…

编辑1

这是将奖品注入到“机会”表中的方式(例如,我创建了一个id为21且该奖品数量为3的奖品)=>它将随机发送给他们(据我所知),但仅限于尚未有award_id的地方(即,如果机会有priest_id
= empty,则可以将其放置在那里)

  SQL (2.4ms)  
  UPDATE "opportunities"
  SET "prize_id" = 21
  WHERE "opportunities"."id" 
  IN (
    SELECT "opportunities"."id"
    FROM "opportunities"
    WHERE (deal_id = 341 AND prize_id IS NULL)
    ORDER BY RANDOM()
    LIMIT 3) //
   (0.9ms)  COMMIT

这个SQL查询是由Rails
gem(称为Randumb:github.com/spilliton/randumb)生成的。


问题答案:

只是一个想法:与其调用random()而不是将其用作列的默认值(可以建立索引),一种类似的方法可以使用增量约为0.7 * INT_MAX的序列。

\i tmp.sql

CREATE TABLE opportunities
    ( id SERIAL NOT NULL PRIMARY KEY
    , deal_id INTEGER NOT NULL DEFAULT 0
    , prize_id INTEGER
    , opportunity_available boolean NOT NULL DEFAULT False
            -- ----------------------------------------
            -- precomputed random() , (could be indexed)
    , magic DOUBLE precision NOT NULL default RANDOM()
    );

INSERT INTO opportunities(deal_id)
SELECT 341
FROM generate_series(1,20) gs
    ;
VACUUM ANALYZE opportunities;

PREPARE add_three (integer) AS (
WITH zzz AS (
  UPDATE opportunities
  SET prize_id = 21
    , opportunity_available = True
    -- updating magic is not *really* needed here ...
    , magic = random()
  WHERE opportunities.id
  IN (
    SELECT opportunities.id
    FROM opportunities
    WHERE (deal_id = $1 AND prize_id IS NULL)
    -- ORDER BY RANDOM()
    ORDER BY magic
    LIMIT 3)
RETURNING id, magic
    ) -- 
SELECT * FROM zzz
    );

PREPARE draw_one (integer) AS (
  WITH upd AS (
  UPDATE opportunities s
  SET    opportunity_available = false
  FROM  (
     SELECT id
     FROM   opportunities
     WHERE  deal_id = $1
     AND    opportunity_available
     AND    pg_try_advisory_xact_lock(id)
     ORDER BY magic
     LIMIT  1

     FOR    UPDATE
     ) sub
  WHERE     s.id = sub.id
  RETURNING s.prize_id, s.id, magic
    )
SELECT * FROM upd
    );

SELECT * FROM opportunities;

\echo add3
EXECUTE add_three(341);
SELECT * FROM opportunities;

\echo add3 more
EXECUTE add_three(341);
SELECT * FROM opportunities;

\echo draw1
EXECUTE draw_one(341);
SELECT * FROM opportunities;

\echo draw2
EXECUTE draw_one(341);
SELECT * FROM opportunities;

VACUUM ANALYZE opportunities;

\echo draw3
EXECUTE draw_one(341);
SELECT * FROM opportunities;

\echo draw4
EXECUTE draw_one(341);
SELECT * FROM opportunities;


 类似资料:
  • 问题内容: 我有一个对话框,其中JTree中的每个条目在不同的面板中都有其相应的选项,当选择更改时会更新该面板。如果将其中一项的选项设置为无效状态,则当用户尝试更改树中的其他项时,我希望出现一个错误对话框,并且选择保持不变。 我尝试使用JTree上的valueChangeListener来执行此操作,但是目前如果有错误,则必须让valueChanged方法将“ setSelectionRow”调用

  • 我知道这个问题之前有人问过,在这里Android禁用最近的任务按钮,就像在SureLock一样,但是既然那里的答案不起作用,也许一些人可以分享一些关于这个被遗忘的事情的光。 我也试过: 但没有运气

  • 问题内容: 根据MySql文档,MySql支持多重粒度锁定(MGL)。 打开终端1: //连接到mysql 离开它打开并打开终端2: //连接到mysql 尽管要检索的行很多,但T2等待直到t1完成。 情况2 保持端子1不变,现在位于端子2中: 但是,为什么在情况1中,T2等待T1锁定的同一行集? 这是否意味着无限制的选择查询(即使使用limint参数。我也尝试了不同的范围)阻塞了整个表? 有什么

  • 问题内容: 我可以找到的最新信息是W3C选择器4级编辑器的草稿,但据我所知,它不再提及父选择器。 我知道有一个关于此的Google调查,但是已经结束了。 父选择器发生了什么?它会被引入还是被移除? 问题答案: 在主题选择告终调查(针对所谓的名不符实“家长选择”适当的名称)与远更灵活替换伪类,这是记录在这里(一个有趣的锚的名字,我不知道这是否会坚持)。 只有在此功能的规范更加稳定时,实现才会实现。目

  • 问题内容: 我创建了以下示例,以便您可以确切了解正在发生的事情:http : //jsfiddle.net/8t2Ln/101/ 如果我使用ng-options,也会发生同样的事情。我这样做有不同的原因,但由于简化了示例,所以省略了这一部分。 如您所见,默认情况下它具有两个选项。我将在选择旁边显示ng- model的选择值,以便您可以看到它的含义。当您在顶部添加第三个选项时,它会将值设置为该新选项

  • 问题内容: 有没有简单的方法来选择更新的行? 我试图每次读取行时都存储时间戳,以便能够删除长时间未读取的数据。 首先,我首先尝试执行查询,甚至发现有点慢但是简单的解决方案,例如 但我仍然想找到一种正常的方法来做到这一点。 我还认为先更新时间然后选择更新的行应该容易得多,但是即使如此,我也没有找到任何东西 问题答案: 声明该列,如下所示: 然后,每当更新一行时,该列就会自动更新。 更新: 我认为没有