繁体   English   中英

MySQL和INT auto_increment字段

[英]MySQL and INT auto_increment fields

我正在开发LAMP(Linux + Apache + MySQL + PHP),因为我记得自己。 但是有一个问题困扰我多年了。 我希望你能帮我找到答案并指出正确的方向。 这是我的挑战:

比如,我们正在创建一个社区网站,我们允许用户注册。 我们存储所有用户的MySQL表看起来像这样:

CREATE TABLE `users` (
  `uid` int(2) unsigned NOT NULL auto_increment COMMENT 'User ID',
  `name` varchar(20) NOT NULL,
  `password` varchar(32) NOT NULL COMMENT 'Password is saved as a 32-bytes hash, never in plain text',
  `email` varchar(64) NOT NULL,
  `created` int(11) unsigned NOT NULL default '0' COMMENT 'Timestamp of registration',
  `updated` int(11) unsigned NOT NULL default '0' COMMENT 'Timestamp of profile update, e.g. change of email',
  PRIMARY KEY  (`uid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

因此,从这个片段中您可以看到,我们为每个新用户的“uid”字段都有一个唯一的自动递增。 与每个良好和忠诚的社区网站一样,如果用户想要取消他们对我们社区的参与,我们需要为用户提供完全删除其个人资料的可能性。

这是我的问题。 假设我们有3个注册用户:Alice(uid = 1),Bob(uid = 2)和Chris(uid = 3)。 现在鲍勃想要删除他的个人资料并停止使用我们的社区。 如果我们从'users'表中删除Bob的个人资料,那么他缺少的'uid'将创建一个永远不会再填充的空白。 在我看来,这是对uid的巨大浪费。 我在这里看到3种可能的解决方

1)将我们表中'uid'字段的容量从SMALLINT(int(2))增加到例如BIGINT(int(8)),并忽略一些uid将被浪费的事实。

2)引入新字段'is_deleted',它将用于标记已删除的配置文件(但将它们保存在表中,而不是删除它们),以便为新注册的用户重新使用它们的uid。 该表看起来像这样:

CREATE TABLE `users` (
  `uid` int(2) unsigned NOT NULL auto_increment COMMENT 'User ID',
  `name` varchar(20) NOT NULL,
  `password` varchar(32) NOT NULL COMMENT 'Password is saved as a 32-bytes hash, never in plain text',
  `email` varchar(64) NOT NULL,
  `is_deleted` int(1) unsigned NOT NULL default '0' COMMENT 'If equal to "1" then the profile has been deleted and will be re-used for new registrations',
  `created` int(11) unsigned NOT NULL default '0' COMMENT 'Timestamp of registration',
  `updated` int(11) unsigned NOT NULL default '0' COMMENT 'Timestamp of profile update, e.g. change of email',
  PRIMARY KEY  (`uid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

3)编写脚本,以便在删除上一条记录后移动所有后续用户记录。 例如,在我们的情况下,当Bob(uid = 2)决定删除他的个人资料时,我们会将他的记录替换为Chris的记录(uid = 3),以便Chris的uid成为2并且标记(is_deleted ='1'克里斯的旧记录是新用户的空缺。 在这种情况下,我们根据注册时间保持uid的时间顺序,以便较旧的用户具有较低的uid。

请告诉我现在哪种方式是处理auto_increment字段中的差距的正确方法。 这只是用户的一个例子,但在我的编程经验中经常出现这种情况。

提前致谢!

绝对不是移动的用户ID想法 - 这将在某些时候杀死你或你的MySQL服务器。 假设你有1,000,000个用户,用户2被删除了 - 你必须将999,999个记录一个向下移动......就像查询一样简单,它仍会锁定你的数据库一段时间。 另外我认为你的auto_increment值会在每个表的每个插页上设置。 插入 - > AI + 1 - >插入 - > AI + 1 - >删除 - > AI保持不变...如果你要移动所有ID,下一个auto_increment值仍然是1,000,001,现在将1,000,000空。

我说未签名的BIGINT并忽略它 - 因为如果你接近bigint的极限,你还有许多其他问题需要解决;)

我写了一个简单的PHP函数来“填充”由“删除”查询引起的auto_increment间隙,并设置正确的“next auto_increment”值。

function mysql_fix_aigap($table,$column){

$fix_aigap=1;

$query_results=mysql_query("select * from $table");

while($row=mysql_fetch_array($query_results)){

mysql_query("update $table set `$column`='$fix_aigap' where `$column` like {$row[$column]};");

$fix_aigap=$fix_aigap+1;

  }

mysql_query("alter table `$table` AUTO_INCREMENT =$fix_aigap");

}

并称之为:

mysql_fix_aigap("gapped_table_to_be_fixed","column"); //"users" and "uid" in your case.

(此脚本假定您已连接到服务器并且已选择数据库!)

这是技术上的答案。

老实说,我不建议为用户名指定一个“变量”uid,这是非精神分裂的方式! (ID =标识)

吨。

首先; 为什么你认为这是uid的“浪费”? 我的意思是,它只是一个整数(或BIGINT),这不再是70年代了。

其次,如果你实施一个建议的选项,你获得的性能损失远远大于你从“浪费”uid中获得的空间损失。 如果某个用户删除了他的个人资料,最糟糕的是,在他之后注册的每个用户都会获得一个新的ID,所以你必须更新非常非常多的记录......

我必须承认,当我刚刚开始编程时,我记得必须习惯自动增量列中的间隙。 但你必须接受它们,继续前进,让它们存在......

我只是忽略了这些差距,并确保您拥有所需的大范围的ID。 差距没有真正的伤害。 试图通过更新数据来修复它们可能会引入更麻烦的破坏关系。

顺便说一句,在MySQL INT(2) ,2指定了最大显示宽度 ,但不影响存储量。 INT(8)使用与INT(2)相同的存储 - 使用BIGINT

unsigned int的最大值是4,294,967,295。 目前的互联网人口约为18亿人。 我建议您使用unsigned int作为目的,不要担心序列中的间隙。

在一个哲学上:Donald Knuth曾经说过“我们应该忘记小的效率,大约97%的时间说:过早的优化是所有邪恶的根源”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM