Typy danych dla identyfikatorów: dlaczego paszport to nie liczba
Proste pytanie o wybór typu danych do przechowywania numeru paszportu w bazie SQL dzieli programistów na tych, którzy myślą o semantyce danych, i tych, którzy działają szablonowo. Błąd w wyborze INTEGER zamiast VARCHAR może prowadzić do utraty zer wiodących i uszkodzonej identyfikacji, co jest krytyczne dla systemów z milionami użytkowników. Ten artykuł omawia fundamentalną zasadę projektowania schematów danych, opartą na naturze informacji, a nie jej wyglądzie.
Semantyka danych a ich forma
Większość programistów na rozmowach kwalifikacyjnych, widząc cyfry w numerze paszportu, automatycznie wybiera typy numeryczne, takie jak INTEGER lub BIGINT. To klasyczny błąd spowodowany powierzchowną analizą. Kluczowe pytanie nie dotyczy tego, z czego składają się dane, ale jak są używane. Z serią i numerem paszportu nigdy nie wykonuje się operacji arytmetycznych — tylko porównuje się je pod kątem równości, wyszukuje i przesyła. To identyfikatory, a nie wartości. Dlatego prawidłowy typ to ciąg znaków: CHAR(4) dla serii i CHAR(6) dla numeru, lub CHAR(10) dla połączonej wartości. Przechowywanie w INTEGER prowadzi do nieodwracalnej utraty zer wiodących: wartość 0306 zamienia się w 306, czyniąc dokument nieważnym bez żadnych błędów w logach.
Praktyczne konsekwencje błędu
Błąd w wyborze typu danych nie jest teoretyczny — regularnie występuje w produkcji. Na przykład, w serwisie do rejestracji abonamentów parkingowych pole paszportu typu NUMBER cicho przycinało zero wiodące, co doprowadziło do niezgodności danych w bazie i na papierze. Incydent przeszedł niezauważony przez przegląd kodu i testowanie, aż dotknął użytkowników z seriami paszportów zaczynającymi się od zera. W Rosji są miliony takich dokumentów, co zwiększa skalę problemu. Argumenty dotyczące optymalizacji, takie jak oszczędność miejsca lub szybkość indeksów, są tutaj nieuzasadnione:
- CHAR(4) zajmuje te same 4 bajty, co INTEGER dla cyfr w kodowaniu jednobajtowym.
- Indeksy na VARCHAR działają z efektywnością O(log n), podobnie jak numeryczne, a różnica w wydajności dla stałych ciągów jest znikoma.
Oszczędność bajtów nie usprawiedliwia ryzyka utraty danych.
Rozszerzenie zasady na inne identyfikatory
Zasada „jeśli nie wykonuje się arytmetyki na danych — to nie jest liczba” ma zastosowanie do wielu identyfikatorów w rosyjskich i międzynarodowych systemach. Rozważmy główne przykłady:
- SNILS (11 cyfr, format XXX-XXX-XXX XX): przechowywać jako VARCHAR(14) lub CHAR(11) po usunięciu myślników, a nie BIGINT.
- INN osoby fizycznej (12 cyfr): może zaczynać się od zera dla regionów 01–09, więc VARCHAR(12) jest obowiązkowe.
- Numer telefonu: tylko VARCHAR(20), aby zachować format z '+' dla numerów międzynarodowych.
- Kod pocztowy: CHAR(6), ponieważ międzynarodowe kody mogą być alfanumeryczne.
- Konto bankowe (20 cyfr): CHAR(20), ponieważ typy numeryczne nie obsługują takich długości bez przepełnienia.
Używanie typów ciągów znaków zapewnia elastyczność i zapobiega utracie danych przy zmianie formatów.
Co jest ważne
- Semantyka jest priorytetem: wybieraj typ danych na podstawie operacji na nich, a nie wyglądu.
- Zera wiodące są krytyczne: typy numeryczne je przycinają, niszcząc identyfikację dla milionów dokumentów.
- Optymalizacja jest drugorzędna: oszczędność bajtów lub mikrosekund nie jest warta ryzyka nieprawidłowych danych.
- Zasada jest uniwersalna: ma zastosowanie do SNILS, INN, telefonów i innych identyfikatorów.
- Sprawdzaj schematy: audyt istniejących baz może ujawnić ukryte luki.
Metodyka wyboru typu danych
Dobry inżynier przy projektowaniu pola w bazie danych zadaje trzy pytania:
- Jaka jest semantyka tych danych? (np. identyfikator, wartość, tekst).
- Jakie operacje będą wykonywane? (porównanie, wyszukiwanie, arytmetyka).
- Jakie ograniczenia nakłada dziedzina? (format, długość, dozwolone znaki).
Odpowiedzi określają wybór: dla identyfikatorów — typy ciągów, dla wartości — numeryczne. To podejście odróżnia rozwiązywanie problemów od mechanicznego pisania kodu i zapobiega kosztownym błędom na wczesnych etapach.
Tabela typów dla rosyjskich identyfikatorów
| Dane | Format | Prawidłowy typ | Częsty błąd | Konsekwencje błędu |
|--------|--------|----------------|---------------|---------------------|
| Seria paszportu | 4 cyfry | CHAR(4) | INTEGER | Utrata zera wiodącego, nieważny dokument |
| Numer paszportu | 6 cyfr | CHAR(6) | INTEGER | Przycięcie zera, uszkodzona identyfikacja |
| Paszport (pełny) | 10 cyfr | CHAR(10) | BIGINT | Utrata do dwóch zer wiodących |
| SNILS | 11 cyfr | CHAR(11) | BIGINT | Przycięcie dla kodów 01–09 |
| INN osoby fizycznej | 12 cyfr | CHAR(12) | BIGINT | Utrata cyfry przy kodzie 01–09 |
| Telefon | +7... | VARCHAR(20) | BIGINT | Niemożność przechowywania '+', niezgodność z formatami międzynarodowymi |
| Kod pocztowy | 6 cyfr | CHAR(6) | INTEGER | Brak wsparcia dla alfanumerycznych kodów międzynarodowych |
| Konto bankowe | 20 cyfr | CHAR(20) | Brak odpowiedniego INT | Przepełnienie, ryzyko błędów finansowych |
Ta tabela służy jako ściągawka do projektowania i audytu schematów baz danych.
— Editorial Team
Brak komentarzy.