MySQL ve INT auto_increment alanlar

5 Cevap php

Kendimi hatırlıyorum beri LAMP (Linux + Apache + MySQL + PHP) gelişmekte ediyorum. Ama bir soru şimdi yıldır beni rahatsız oldu. Ben bir cevap bulmak ve doğru yönde bana gelin bana yardımcı olabilir umuyoruz. İşte benim bir sorundur:

Say, bizim kullanıcıların kayıt için izin bir topluluk web sitesi yaratıyor. Tüm kullanıcıları saklamak MySQL tablo bu böyle sonra görünecektir:

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;

Yani, bu pasajı sizi her yeni kullanıcı 'uid' alanı için artan otomatik olarak benzersiz ve sahip olduğunu görebilirsiniz. Her iyi ve sadık bir topluluk web sitesinde biz onlar bizim toplumda onların katılımını iptal etmek istiyorsanız, tamamen kendi profilini silmek olanağı sunmak gerekir.

İşte benim sorun gelir. Alice (uid = 1), Bob (uid = 2) ve Chris (uid = 3): Hadi biz 3 kayıtlı kullanıcımız var diyelim. Şimdi Bob onun profilini silmek ve topluluğumuza kullanarak durdurmak istiyor. Biz 'kullanıcılar' tablosundan Bob'un profili silin sonra onun eksik 'uid' tekrar doldurulabilir asla olacak bir boşluk yaratacaktır. Bence o uid yıllardan büyük bir israf var. Burada 3 olası çözümleri bakın:

1) SMALLINT (int (2)), örneğin, BIGINT (int (8)) bizim tabloda 'uid' alanının kapasitesini artırın ve uid yıllardan bazı boşa olacağı gerçeğini görmezden.

2) silinen profilleri işaretlemek (ama yeni kayıtlı kullanıcılar için yeniden kullanmak kendi uid adlı) bunları silmek yerine, masaya onları tutmak için kullanılacak 'is_deleted' yeni alanı, tanıtmak. Tablo bu gibi sonra görünecektir:

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) Bir önceki rekor silindikten sonra aşağıdaki tüm kullanıcı kayıtları kaydırmak için bir komut dosyası yazın. Örneğin bizim durumumuzda zaman Bob (uid = 2) Chris o uid 2 ve işareti (is_deleted = '1 ') için qual olur böylece, biz Chris (uid = 3) ve kayıt ile yaptığı rekor yerini alacak, onun profilini kaldırmak için karar yeni kullanıcılar için boş olarak Chris eski rekor. Eski kullanıcılara düşük uid bulunuyor olması, böylece bu durumda biz, uid adlı kayıt zamana göre kronolojik sırasını tutmak.

, Auto_increment alanlardaki boşlukları işlemek için doğru yolu olan yolu artık beni tavsiye edin. Bu kullanıcı ile sadece bir örnektir, ama bu gibi durumlarda benim programlama deneyimi çok sık görülür.

Şimdiden teşekkürler!

5 Cevap

definitely not the moving user ids idea - that will kill you or your mysql server at some point. lets say you have 1,000,000 users and user 2 gets deleted - you had to shift 999,999 records one down... as simple as the query would be it would still lock your db for a while. also i think that messes with your auto_increment value which is set on each insert for each table. insert -> AI+1 -> insert -> AI+1 -> delete -> AI stays the same... if you would shift all the ID's the next auto_increment value would still be 1,000,001 which would now leave 1,000,000 empty.

i imzasız Bigint söylemek ve bunu görmezden - nedenini size çözmek için birçok sorunları var bigint sınırına bile yakın gelirse ;)

Ben "delete" sorgulama neden auto_increment boşlukları "doldurmak" ve doğru "bir sonraki auto_increment" değerini ayarlamak için basit bir PHP işlevi yazdı.

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");

}

ve onu çağırır:

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

(Bu komut zaten sunucuya bağlı ve veritabanı seçmiş olduğunu varsayar!)

Ve bu teknik cevap oldu.

Dürüst Bence, ben adı bir "değişken" uid atamak tavsiye etmem, bu non-schizophrenical yolu! (Id = kimlik)

t.

Öncelikle; neden bunu uid bir "atık" olduğunu düşünüyor musunuz? Ben sadece bir tamsayı (ya da BIGINT) var, yani bu artık 70 değil.

İkincisi, önerilen seçeneklerden birini uygulamak eğer olsun performans kaybı oluyor "israf" uid almak mekansal kaybı daha büyüktür. Bazı kullanıcı en kötü onun tercihi, yeni bir id alır ondan sonra kayıtlı her kullanıcının siler Eğer öyleyse çok çok kayıtları güncellemek zorunda ...

Ben sadece otomatik artış sütunlarındaki boşluklar alışmak zorunda hatırlamıyorum programlama başladı ben, itiraf etmeliyim. Ama, bunları kabul hareket, ve sadece onları var izin vermek zorunda olacak ...

Ben sadece boşlukları görmezden ve gerektiği gibi kimlikleri gibi geniş bir ürün yelpazesi var sağlamak olurdu. Boşluklar gerçek zarar. Verileri güncelleyerek bunları düzeltmek için çalışırken daha fazla sorun vardır kırık ilişkileri tanıtmak olabilir.

MySQL arada INT(2) 2 maximum display width belirtir, ancak depolama miktarını etkilemez. Dediğiniz gibi BIGINT kullanın - INT(8) INT(2) olarak aynı depoyu kullanır.

Bir imzasız int maksimum değeri 4,294,967,295 olduğunu. İnternetin şimdiki nüfusu yaklaşık 1,8 milyar insan olduğunu. Ben amaçlar için işaretsiz int kullanarak tavsiye ediyorum ve sizin dizisi boşluklar hakkında endişelenmeyin.

Felsefi bir not: Donald Knuth kez ": prematüre optimizasyon tüm kötülüklerin köküdür Biz zaman yaklaşık% 97 demek, küçük verimlilik unutun gerekir" dedi.