保证字段值是连续的序列

时间:2011-11-06 20:27:38

标签: mysql sql

我有一张这样的表

mysql> describe obj;
+----------+----------+------+-----+---------+----------------+
| Field    | Type     | Null | Key | Default | Extra          |
+----------+----------+------+-----+---------+----------------+
| id       | int(11)  | NO   | PRI | NULL    | auto_increment |
| data     | blob     | YES  |     | NULL    |                |
| sequence | int(11)  | YES  | UNI | NULL    |                |
| created  | datetime | YES  |     | NULL    |                |
+----------+----------+------+-----+---------+----------------+

我希望字段sequence中的值是连续的序列,即没有跳过和跳跃,并且基于created时间戳。目前我在应用程序级别获得此功能。每次插入后:

while (true)
   lastSequence = max(sequence)
   if (update obj with lastSequence + 1)
      break

这种方式无法跳过,但无法保证sequence订单与created订单相同。另一方面,我可以通过created在子查询中进行排序,但是在一个cuncurrent环境中,如果我没有序列化所有写入,子查询执行时可能会发生奇怪的事情,但我认为这会扼杀性能。关于这个问题的任何想法?

2 个答案:

答案 0 :(得分:2)

没有灵丹妙药。

自动增加ID号无效,因为如果事务回滚,您将获得间隙。

交易外的应用程序代码不起作用,因为它无法保证“序列”的顺序与“已创建”的顺序相匹配。

在单个可序列化的事务中完成所有工作将起作用,但肯定会影响性能。它是否如此影响性能是不可用的是一个悬而未决的问题;测试和测量。

这样的事情(PostgreSQL)应该可行,但可能不够快。 (按照下面的时间用一粒盐。没有并发用户,小桌子。)

set transaction isolation level serializable;
begin;

insert into obj (sequence, time_created)
select min(n), current_timestamp 
from serial_integers where time_stamp is null;
-- 0.125ms

update serial_integers
set time_stamp = current_timestamp
where n = (select min(n)
from serial_integers where time_stamp is null);
-- 0.161ms

commit;
-- 15ms

实际上,我测试将它包装在一个函数(存储过程)中,部分是为了消除UPDATE语句中的子查询。

答案 1 :(得分:1)

在MySQL中,您使用auto_increment就像在ID字段中使用一样。

在oracle中你会使用音序器。

这个问题已存在多年。问题是当你确定MAX(值)时你必须锁定东西,因为你不能确定另一个进程没有插入另一个记录。

如果您删除记录,

会发生 差距。如果要使用日期/时间值,则必须降低到亚毫秒级别,因为数据库非常快。 Oracle使用systimestamp,它至少将秒数带到6个位置。