<p>临时表和事务应保持原子性和排序顺序的唯一约束。要重新说明问题,请从以下位置开始:</p>
<pre><code>A 10 to B 10
B 25 C 25
C 26 E 26
E 34 A 34
</code></pre>
<p>每行之间可以有任意数量的项。所以,首先读入记录并创建一个列表<code>[['A',10],['B',25],['C',26],['E',34]]</code>。通过一些pythonic魔术,您可以移动标识符并将其插入临时表中:</p>
<pre><code>create temporary table reorder (
id varchar(20), -- whatever
sort_order number,
primary key (id));
</code></pre>
<p>现在更新:</p>
<pre><code>update table XYZ
set sort_order = (select sort_order from reorder where xyz.id = reorder.id)
where id in (select id from reorder)
</code></pre>
<p>我只是假设pgsql可以处理这个查询。如果可以,它将是原子的。</p>
<p>可选地,将表REORDER创建为永久表,事务将确保两次对同一记录重新排序的尝试将被序列化。</p>
<hr/>
<p>编辑:有一些事务问题。你可能需要实现我的两个想法。如果两个进程都希望更新项B(例如),则可能会出现问题。因此,假设所有的顺序值都是偶数:</p>
<ol>
<li>开始交易</li>
<li>增加1正在使用的所有订单。这将对要更新的所有行设置行级写锁。</li>
<li>如果任何<code>sort_order</code>字段甚至是某个其他进程添加了与您的条件匹配的记录,请选择您刚刚更新的数据。您可以中止事务并重新启动,也可以只使用在步骤2中更新的记录来删除记录并完成操作。要做的“正确”的事情取决于您需要这些代码来完成什么。</li>
<li>使用正确的偶数排序顺序填写上述临时重新排序表。</li>
<li>如上所述更新主表。</li>
<li>放下临时表。</li>
<li>提交事务</li>
</ol>
<p>步骤2确保如果两个列表重叠,则只有第一个列表可以访问行
在交易完成前存在疑问:</p>
<pre><code>update XYZ set sort_order = sort_order + 1
where -- whatever your select criteria are
select * from XYZ
where -- same select criteria
order by sort_order
</code></pre>
<p>或者,可以向表中添加一个控件字段以获得相同的效果,然后不需要使用<code>sort_order</code>字段。使用<code>sort_order</code>字段的好处是,当字段通常为空时,使用位字段或<code>LOCK_BY_USERID</code>字段进行索引往往性能较差,因为索引99%的时间没有意义。SQL引擎不喜欢大部分时间都是空的索引。</p>