2010-05-26 73 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。