英语不是我的母语,因此我对任何语法错误深表歉意。
我有以下MySQL表(为易于理解而简化):
users (InnoDB - utf8_general_ci):
- usr_Id: int(11) unsigned Auto_Increment
- usr_Username: varchar(50)
- usr_Password: varchar(50)
messages (InnoDB - utf8_general_ci):
- msg_Id: int(11) unsigned Auto_Increment
- msg_UserId: int(11) unsigned
- msg_Date: datetime
- msg_Subject: varchar(50)
- msg_Text: varchar(1024)
有一个简单的Web界面(PHP),用户可以在其中登录以查看其消息:
SELECT msg_Id, msg_Subject FROM messages WHERE msg_UserId = <Logged User Id> ORDER BY msg_Date DESC;
一旦用户单击列表上的消息主题,就会显示带有消息的弹出窗口:
SELECT msg_Text FROM messages WHERE msg_Id = <Id From Clicked Message>;
cronjob每天凌晨4点会自动删除所有3个月以上的邮件:
DELETE FROM messages WHERE msg_Date < DATE_SUB(NOW(), INTERVAL 3 MONTH);
所以,这是我的问题:该系统目前正在测试约5个月,用户数不到100,而msg_Id已经是91451!实际使用时,预计至少会有2000-5000个用户!
一旦较旧的消息被自动删除,并且我不使用msg_Id链接不同的表,我想知道我是否可以在一段时间后“重用”第一个ID,也许阻塞服务器几分钟来执行“重置”过程ID?还是有更简单的方法?拜托,我有什么选择?
谢谢!
答案 0 :(得分:1)
甚至不用考虑重用AUTO_INCREMENT
值;这不值得麻烦。甚至不要考虑重新发明这个轮子。其中内置了许多不错的功能。
做一些数学运算。如果您认为可能超过40亿行,请将msg_id
从INT UNSIGNED
更改为BIGINT UNSIGNED
。一百万BIGINTs
将比INT
多占用4MB。 (如果有二级索引,则更多。)
(可选)不要在列名前加上表名来使SQL混乱。)
考虑使用PARTITION BY RANGE(TO_DAYS(msg_Date))
帮助有效地删除旧数据。
算一下! 91451 * 5000/100 / 5 =每月只有100万行。即使不重复使用ID,也需要3个世纪的时间才能达到40亿个。
91K行是一个“小”表。具有十亿行的表是“大”的,但可行的。
所需索引:
具有分区功能(请参见this):
PRIMARY KEY(UserId, Date, msg_id),
INDEX(msg_id)
不分区:
PRIMARY KEY(Date, msg_id),
INDEX(msg_id),
INDEX(UserId, Date)
这些将有效地支持您提供的SELECTs
。
警告:某天会有一个用户收到数千条消息。您的第一个SELECT
可能比预期的要慢,或者可能会在UI中引起麻烦。我选择的索引会有所帮助。