我们的应用程序调用存储过程将其数据规范化为引用表,之后它将一条记录插入到主表中,该记录部分包含值并部分包含映射到引用表的ID。这是存储过程之一:
CREATE PROCEDURE `sp_name`(IN valueIn varchar(100), OUT valueOut int)
BEGIN
declare maxid int;
declare countid int;
select max(id) into valueOut from tableName where fieldName=valueIn;
IF valueOut is NULL
THEN
start transaction with consistent snapshot;
select count(*) into countid from tableName where fieldName=valueIn;
IF countid=0
THEN
insert into tableName (fieldName) values (valueIn);
select last_insert_id() into valueOut;
ELSE
select max(id) into valueOut from tableName where fieldName=ValueIn;
end IF;
commit;
end IF;
END
手动调用时,这可以正常工作,但在生产中调用时,我们最终会在参考表中出现多个重复值。
事务隔离级别为REPEATABLE_READ。
参考表:
CREATE TABLE `tableName` (
`id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`fieldName` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8
在字段fieldName上使用唯一键约束不是一个不错的选择。我们尝试了这个,但是后来我们发现自动增量没有获取重复值,而是跳过了ID。我们正在尝试保留ID,以便在数据类型方面不需要过度分配。我们的主表是巨大的(数十亿),因此我们必须有效地使用数据类型。
有谁了解这种现象?
答案 0 :(得分:1)
如果你想为auto_increment构建自己的替代品,你必须清除很多障碍。您将发现可串行化,并发性,性能(通常与锁定相关)等问题。
我认为最简单的解决方案可能是在bigint unsigned
类型的列上使用auto_increment。无符号整数的最大值是4,294,967,295:大约4x10 ^ 9。 unsigned bigint的最大值为18,446,744,073,709,551,615:大约1.8x10 ^ 19。
auto_increment仍会跳过id号码,但这是设计的,并且它不应该导致1.8x10 ^ 19范围内的麻烦。
在您开始使用此路径之前,请使用您的客户端软件测试大数字。有些人仍然没有与bigint妥协,无论是否签名。