Php MySQL和INT自动递增字段

Php MySQL和INT自动递增字段,php,mysql,phpmyadmin,auto-increment,Php,Mysql,Phpmyadmin,Auto Increment,自从我记得自己以来,我一直在LAMP(Linux+Apache+MySQL+PHP)中开发。但有一个问题多年来一直困扰着我。我希望你能帮我找到答案,并为我指出正确的方向。这是我的挑战: 比如说,我们正在创建一个社区网站,允许用户注册。存储所有用户的MySQL表如下所示: CREATE TABLE `users` ( `uid` int(2) unsigned NOT NULL auto_increment COMMENT 'User ID', `name` varchar(20) NOT

自从我记得自己以来,我一直在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;
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;
因此,从这段代码中,您可以看到,对于每个新用户的“uid”字段,我们都有一个唯一且自动递增的字段。在每一个好的和忠诚的社区网站上,我们需要为用户提供完全删除他们的个人资料的可能性,如果他们想取消他们在我们社区的参与

我的问题来了。假设我们有3个注册用户:Alice(uid=1)、Bob(uid=2)和Chris(uid=3)。现在Bob想删除他的个人资料并停止使用我们的社区。如果我们从“用户”表中删除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,
  `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;
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,并将Chris的旧记录标记为(is_deleted='1'),以供新用户使用。在这种情况下,我们根据注册时间保持uid的时间顺序,以便年龄较大的用户具有较低的uid

请现在告诉我哪种方法是处理自动增量字段中的间隙的正确方法。这只是用户的一个例子,但在我的编程经验中,这种情况经常发生


提前谢谢

绝对不是移动用户ID的想法-这会在某个时候杀死你或你的mysql服务器。 假设您有1000000个用户,用户2被删除-您必须将999999条记录向下移动一次。。。尽管查询很简单,但它仍会锁定数据库一段时间。 另外,我认为这会影响在每个表的每个插入上设置的自动增量值。 插入->AI+1->插入->AI+1->删除->AI保持不变。。。如果将所有ID移位,下一个自动增量值仍将为1000001,这将使1000000留空


我说unsigned BIGINT并忽略它——因为如果你接近BIGINT的极限,你还有很多其他问题需要解决;)

首先;你为什么认为这是对UID的“浪费”?我的意思是,它只是一个整数(或BIGINT),现在已经不是70年代了

其次,如果您实现了您建议的选项之一,那么您所得到的性能损失远远大于“浪费”UID所带来的空间损失。如果某个用户删除了他的个人资料,最坏的情况是,在他之后注册的每个用户都会得到一个新的id,所以你必须更新非常非常多的记录


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

我会忽略这些差距,确保您拥有所需的尽可能多的ID。这些差距并没有造成真正的伤害。试图通过更新数据来修复它们可能会导致更麻烦的关系破裂


顺便说一下,在MySQL
INT(2)
2中,2指定了存储空间,但不影响存储量
INT(8)
使用与
INT(2)
相同的存储空间-按您的意思使用。

无符号INT的最大值为4294967295。目前互联网人口约为18亿。我建议出于您的目的使用无符号int,不要担心序列中的间隙


从哲学角度讲:Donald Knuth曾说过“我们应该忘记小效率,比如说97%的时间:过早优化是万恶之源”。

我编写了一个简单的PHP函数来“填补”由“删除”查询导致的自动增量缺口,并设置正确的“下一个自动增量”值

并称之为:

mysql_fix_aigap("gapped_table_to_be_fixed","column"); //"users" and "uid" in your case.
(此脚本假定您已连接到服务器,并且已选择数据库!)

这就是技术上的答案

老实说,我不建议给用户名分配一个“变量”uid,这不是精神分裂症!(id=身份)


t、

可能重复感谢莱克斯的意见,正如你所说,我必须像你曾经做的那样适应自动增量的差距!非常感谢你!我现在接受空白:)就像最后一句;)18446744073709551615 ID可用于bigint。。。我想这肯定解决了“缺口”的问题——举个例子:如果你有300000000个用户(facebook大小),那么每个用户都必须删除他们的帐户,并创建一个超过60亿次的新帐户,直到你的ID用完为止;)