INT(11) kontra INT

Na wielu forach i grupach widzę, iż często w kodzie zapytań tabel jest INT(11). Zdaję sobie sprawę, iż czasami jest to spowodowane skopiowaniem zapytania z jakiegoś programu, który automatycznie nam z jakiegoś powodu coś takiego dodaje. Częściej jednak jest to stosowane przez programistów z premedytacją wynikającą poprostu z niewiedzy. Postaram się tutaj tę sprawę wyjaśnić.

Weźmy jako przykład poniższy kod tworzący tabelę autorstwa pana X

create table `test` (
  `ID` int(11) unsigned NOT NULL auto_increment,
  `TYPE` int(1) unsigned NOT NULL default 0 COMMENT 'typy. mozliwe wartosci 1,2,3,4',
  `BLABLA` varchar(64) NOT NULL default '' COMMENT 'blabla',
  `PRODUCTS_COUNT` int(5) unsigned NOT NULL default 0 COMMENT 'liczba produktów. Nie przekroczy 50tys',
    PRIMARY KEY  (`ID`),
  KEY `TYPE` (`TYPE`)
) ENGINE=InnoDB;

Jak widzicie wszystkie pola liczbowe są typu INT. Przy każdym z pól określono w nawiasie jakąś liczbę. Patrząc po tych liczbach, można wnioskować, iż autor tego zapisu chciał ograniczyć zakres pola. I tak np. (1) ma oznaczać liczby jednocyfrowe, czyli do 9, a zapis (5) ma niby oznaczać liczby 5-cio cyfrowe.

Otóż autor tego zapytania jest w błędzie. Liczby w nawiasach przy typach z rodziny INT służą tylko i wyłącznie w przypadku, gdy używamy ZEROFILL. A że opcji tej w większości przypadków się nie używa (sam jej raz przez pomyłkę użyłem a potem bardzo żałowałem) to nie bedę na jej temat nic pisał, uznając na potrzeby tego artykułu, że jej w ogóle nie ma.

Tak więc zapis INT(1) nie ogranicza nas w żaden sposób do maksymalnie liczby 9 i w żaden sposób taka kolumna nie będzie zajmowała jednego bajta tylko nadal 4 jak każdy INT. Jeśli chcemy ograniczyć nasze pole do jednego bajta to poprostu użyjmy TINYINT. Jeśli chcemy ograniczyć kolumnę do 50tys (a konkretnie 65535) to używamy nie INT(5) tylko SMALLINT. Dopiero takie użycie typów kolumn ogranicza ilość bajtów zajmowanych przez pole i dopiero wówczas mamy optymalnie pisany kod pod względem rozmiarów pól liczbowych

Ostatecznie więc nasze zapytanie tworzące tabelę powinno wyglądać tak:

create table `test` (
  `ID` int unsigned NOT NULL auto_increment,
  `TYPE` tinyint unsigned NOT NULL default 0 COMMENT 'typy. mozliwe wartosci 1,2,3,4',
  `BLABLA` varchar(64) NOT NULL default '' COMMENT 'blabla',
  `PRODUCTS_COUNT` smallint unsigned NOT NULL default 0 COMMENT 'liczba produktów. Nie przekroczy 50tys',
    PRIMARY KEY  (`ID`),
  KEY `TYPE` (`TYPE`)
) ENGINE=InnoDB;

Przy okazji zwróćcie uwagę na unsigned, które jest przy każdym polu liczbowym. Jeśli pole będzie przyjmować tylko wartości dodatnie (i zero) to warto dla tego pola zaznaczyć, iż to pole właśnie takie będzie. Chociażby po to, że przez dodanie unsigned zwiększa nam się zakres przyjmowanych wartości bez zmiany ilości zajmowanych bajtów. I tak np. TINYINT może osiągnąć max 127, zaś UNSIGNED TINYINT już 255. Analogicznie pozostałe typy liczbowe.

Komentarze

 

2011-02-04 00:56 gość_Tomasz Kowalczyk

Wiele programów - np MySQL Workbench generuje kod właśnie z INT(11) - ja jakoś specjalnie nie zwracałem na to nigdy uwagi, bo nigdy nie przekroczyłem tego zakresu, ale dobrze, że wypomniałeś, ponieważ nie każdy wie, że wcale nie musi być tam "11" - może być dowolna inna liczba, albo wcale. ;]

2011-02-04 06:31 gość_greg606

Tak samo robi phpmyadmin. I chyba nawet nie ma tego specjalnie jak usunąć

2011-02-04 07:13 nospor

No niestety na programy nic nie poradzę Jednak takie programy przez takie zagrywki wprowadzają użytkowników w błąd. Przyznam szczerze, iż sam kiedyś myślałem, że właśnie to ta liczba w nawiasie ogranicza zakres pola i sam bezmyślnie stosowałem jej różne wariacje. Sam już nie pamiętam kiedy mnie olśniło - chyba przez przypadek posiadłem tę więdzę tajemną Niestety dużo osób nadal tego nie wie, nawet tych bardziej doświadczonych (miałem i takie przypadki) więc postanowiłem o tym wspomnieć na łamach bloga - mam nadzieję że skorzystacie

2011-02-04 09:27 gość_sokzzuka

Ha, to teraz pytanie skoro liczba przy int(11) nie służy do tego co się nam wydawało, więc do czego właściwie służy :> ?

2011-02-04 09:33 nospor

Napisałem przecież w arcie, że do ZEROFILL Napisałem również, że chyba nikt tego nie używa więc nie będę się na ten temat nawet rozpisywał
No ale dobra, ZEROFILL służy do wypełniania liczb w bazie zerami, gdy dana liczba zajmuje mniej miejsca niż to określiłeś. Jeśli więc określisz INT(5) a w bazie masz liczbę 123 to ta liczba zostanie zapisana w bazie jako 00123. Taki bajer
Jak już raz pisałem raz użyłem tego "bajeru" i potem gorzko żałowałem.
http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html
When used in conjunction with the optional (nonstandard) attribute ZEROFILL, the default padding of spaces is replaced with zeros. For example, for a column declared as INT(4) ZEROFILL, a value of 5 is retrieved as 0005.

2011-02-04 20:04 gość_Crozin

1. Wartości dodatnie i zero to po prostu wartości nieujemne.
2. Przed użyciem UNSIGNED należy zastanowić się czy aby na pewno go potrzebujemy. W zdecydowanej większości przypadków bardziej opłaca się użyć obszerniejszego typu (np. BIGINT zamiast UNSIGNED INT) niż wprowadzać typ bez znaku, który komplikuje wiele spraw.

2011-02-04 20:12 nospor

ad1) Ja to wiem, Ty to wiesz, ale założe się że znalazłaby się osoba, która zadałaby pytanie: "a co to liczby nieujemne"
ad2) Możesz podać choć ze dwie sprawy, które komplikuje użycie unsigned? Osobiście nie widzę sensu dawać większego pola, zajmującego więcej bajtów tylko dlatego że... no właśnie dlaczego?

2011-02-04 23:32 gość_JoShiMa

Póki co nie udało mi się w phpMyAdmin wstawić do tabeli pola typu int bez podania mu wartości. Taka przypadłość.

Co do unsigned, to odkryłam, że w MySQL jest niezbędne przy indeksach jeśli chcemy użyć ich jako kluczy obcych w relacjach między tabelami.

2011-02-10 19:38 gość_Kevin

Świetnie napisany artykuł, brakowało wyjaśnienia dotyczącego ZEROFILL, ale widzę w komentarzach już odpowiedź ;-)

2011-10-14 09:40 gość_Emtec

Crozin nie masz racji. Czemu masz używać BIGINT które zajmuje więcej miejsca i dłużej jest obliczane. Każdy przedział lub raczej MAX VALUE (każdego typu) jeśli jest ze znakiem (czyli domyślnie) jest "dzielone" na dwa częsci. Jedne są od minus do 0 i od 0 do plusa. Zaznaczenie że "dane" mają być bez znaku oznacza tylko że przedział od "minus do 0" jest pakowany w zestaw możliwości od 0 do plusa. Czyli ten sam rozmiar, a nasze ID może na zwykłym INT uzyskać więcej wartości. Do tego masz 100% pewność że nasze ID nigdy nie będzie miał wartość ujemną. W większości skryptów - ID jest wypełniane automatem czyli LAST_ID + 1, co sprawia że zawsze wartość będzie dodatnia, więc jeśli jesteś pewny że tylu elementów w tablicy nie będzie żeby używać BIGINT-a to wystarczy mu dać właśnie flagę unsigned.

2013-12-02 08:25 gość_Damian

Bardzo przydał mi się ten artykuł. Też nigdy wcześniej nie zwracałem uwagi na wartość INT.

Pozdrowienia dla autora

2014-01-22 21:13 gość_Jarek

Ja zauważyłem taką zależnośc, kiedy phpMyAdmin tworzę pole tabeli "int" powstaje zapis int(11), kiedy tworzę pole tablli "int unsigned" to powstaje zapis int(10). Wychodzi na to, że jest ilośc znaków. Do zapisu wartosci ujemnych int potrzeba razem ze znakiem minus "-" 11 znaków, do zapisu liczby int bez znaku(unsigned) potrzeba 10 znaków. Ilośc mozliwosci zapisu liczb jest w każdym przypadku taka sama, jednak zmienia się zakres (-2147483648 do +2147483647 lub 0 do 4294967295) i w tym przypadku ilosc potrzebnych znaków do ich zapisania.

2014-01-22 22:02 nospor

@Jarek dopoki pole nie jest ZEROFILL to nie ma znaczenia czy masz int 11, 10 czy int1

Dodaj komentarz

 

Dostępne bbcode: b, u, i, url, code, php, css, html, sql, js

Ostatnio komentowane

  1. Mysql - FAQ Paweł
  2. Pager 2.5.1 oraz EPa... Na szybko2
  3. Pager 2.5.1 oraz EPa... Sławek
  4. Mysql - FAQ Piotr
  5. Liczba dni roboczych Na szybko2
  6. Liczba dni roboczych Naszybko
  7. Klasa widoku nospor

Skrypty użytkowników

  1. Klasa obsługi szablo... Lirdoner
  2. Sekcje user76
  3. Klasa walidująca for... user76
  4. Licznik Gości online korey
  5. Form Builder Comandeer
  6. Dynamiczny licznik z... korey
  7. Captcha Comandeer