2010-05-26 71 views
3

自从我记得自己以后,我在LAMP(Linux + Apache + MySQL + PHP)中开发。但现在有一个问题困扰着我多年。我希望你能帮助我找到答案,并指引我走向正确的方向。这是我的挑战:MySQL和INT auto_increment字段

说,我们正在创建一个社区网站,我们允许我们的用户注册。我们存储所有用户看起来那么像这样的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)。现在鲍勃想要删除他的个人资料并停止使用我们的社区。如果我们从'用户'表中删除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字段中的空白。这只是用户的一个例子,但这种情况经常出现在我的编程经验中。

提前致谢!

+0

可能的重复[何时修复MYSQL中的自动递增间隔](http://stackoverflow.com/questions/1949842/when-to-fix-auto-increment-gaps-in-mysql) – 2010-05-26 07:16:06

回答

2

绝对不是移动用户ids的想法 - 这会杀了你或你的MySQL服务器在某个时刻。 可以说你有1,000,000个用户,而用户2被删除 - 你必须将999,999个记录向下移动一次...就像查询那样简单,它仍然会锁定你的数据库一段时间。 也我认为,与每个表的每个插入设置的auto_increment值混淆。 insert - > AI + 1 - > insert - > AI + 1 - > delete - > AI保持不变...如果您要移动所有ID,那么下一个auto_increment值仍然是1,000,001,现在会留下1,000,000空。

我说无符号BIGINT,而忽略它 - 因为如果你来甚至接近BIGINT的极限你有很多其他的问题需要解决;)

+0

非常感谢许多!我会接受现在的差距:)像最后一句话:)) – PHPguy 2010-05-26 07:36:48

+1

18,446,744,073,709,551,615 ID可用于bigint ...猜测肯定解决了“差距”的问题 - 就像一个例子那么多:如果你有300,000,000用户(Facebook的大小),每个用户将不得不删除他们的帐户,并创建一个新的超过60亿次,直到你用完ID;) – Tobias 2010-05-26 23:37:26

0

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

其次,如果您实施您的某个建议选项,则会导致性能损失远远大于您从“浪费”uid获得的空间损失。如果某个用户删除了他的个人资料,最坏情况下,每个注册他的用户都会得到一个新的ID,因此您必须更新非常非常多的记录...

我必须承认,当我刚开始编程时,以适应自动增量列中的空白。但你将不得不接受他们,继续前进,并让他们存在...

+0

谢谢你的意见,因为你说Lex我必须习惯于差距像你曾经做过的那样,auto_increment! – PHPguy 2010-05-26 07:35:45

0

我只是忽略了差距,并确保你有需要的范围广泛的ids。差距没有真正的伤害。试图通过更新数据来解决这些问题可能会导致更为麻烦的破坏关系。

顺便说一下,在MySQL INT(2)中,2指定了maximum display width,但不影响存储量。 INT(8)使用与INT(2)相同的存储 - 使用BIGINT就像你暗示的那样。

+0

谢谢Martin! – PHPguy 2010-05-26 07:37:15

0

无符号整数的最大值是4,294,967,295。目前互联网人口约为18亿人。我建议使用一个无符号的整数为你的目的,不要担心你的序列中的差距。

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

1

我写了一个简单的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. 

(!此脚本假定您已经连接到服务器,您所选择的数据库)

而且这是技术性的答复。

在我诚实的意见,我不会建议分配一个“变量”用户名,这是非精神分裂的方式! (id = identity)

t。