- Tabela ma jedną kolumnę i jedno zadanie: wydawać numery unikalne w skali całej bazy, nie pojedynczej tabeli.
- Numer referencyjny wiąże rekord z jego historią, blokadami, potwierdzeniami i danymi mapowymi bez oglądania się na tabelę źródłową.
- Typ
bigintdaje zakres ponad dziewięciu trylionów wartości — wyczerpanie go nie jest realnym zagrożeniem. - Klucz główny na jedynej kolumnie wyklucza wydanie tego samego numeru dwa razy.
Do czego służy tabela [dbo].[_refno]
Większość tabel w bazie ma własny klucz — ID_HISTORIA, ID_ERROR, ID_JOBS. Są to numery lokalne: pierwszy wiersz każdej z nich ma identyfikator 1. Dopóki rekordy nie muszą wskazywać na siebie nawzajem, wystarcza to w zupełności. Problem pojawia się, gdy jedna tabela ma odwoływać się do rekordu z dowolnej innej.
Tak działają w StudioSystem rejestry pomocnicze. Historia zmian, blokady edycyjne, potwierdzenia przeczytania i współrzędne geograficzne odwołują się do rekordu przez numer referencyjny — i muszą to robić niezależnie od tego, czy rekord jest dokumentem magazynowym, kontrahentem czy zleceniem. Numer lokalny by tu nie wystarczył, bo wartość 1 oznaczałaby coś innego w każdej tabeli.
Tabela [dbo].[_refno] rozwiązuje to najprościej, jak można: jest centralnym rejestrem wydanych numerów. Nowy rekord pobiera z niej kolejną wartość, która od tej chwili identyfikuje go w całej bazie. Klucz główny na jedynej kolumnie gwarantuje, że ten sam numer nie zostanie wydany dwukrotnie — i to jest właściwie cała mechanika.
Wartość tego rozwiązania polega na tym, że rejestr pomocniczy nie musi wiedzieć, z jakiej tabeli pochodzi opisywany rekord.
Budowa tabeli — wykaz kolumn
Struktura obejmuje jedną kolumnę — i nie potrzebuje więcej, bo całe zadanie tabeli sprowadza się do wydawania niepowtarzalnych wartości.
| Kolumna | Typ | Wymagana | Znaczenie |
|---|---|---|---|
REFNO | bigint liczba całkowita 64-bitowa | tak | Unikalny numer referencyjny wykorzystany w systemie |
Typ bigint obejmuje zakres do 9 223 372 036 854 775 807. Przy milionie nowych rekordów dziennie wyczerpanie tej puli zajęłoby ponad dwadzieścia pięć miliardów lat, więc jest to problem czysto teoretyczny.
Indeksy i wydajność zapytań
Jedyny indeks pełni tu funkcję wykraczającą poza przyspieszenie odczytu.
| Indeks | Kolumny | Rodzaj |
|---|---|---|
PK__refno | REFNO | klucz główny |
Klucz główny na kolumnie REFNO jest mechanizmem, na którym opiera się cała gwarancja niepowtarzalności. Próba wstawienia istniejącej już wartości kończy się błędem po stronie serwera — a więc ochrona działa także wtedy, gdy dwa procesy sięgną po numer w tej samej chwili, czego sprawdzenie w kodzie aplikacji nie zapewnia.
Centralny rejestr a inne sposoby nadawania identyfikatorów
SQL Server oferuje kilka mechanizmów generowania unikalnych wartości. Każdy z nich sprawdza się w innym zastosowaniu, a różnice mają praktyczne konsekwencje dla wydajności i wielkości bazy.
| Mechanizm | Zakres unikalności | Rozmiar | Kolejność zapisu |
|---|---|---|---|
Centralny rejestr (_refno) | Cała baza danych | 8 bajtów | Rosnąca — zapisy trafiają na koniec indeksu |
Kolumna IDENTITY | Pojedyncza tabela | 4 lub 8 bajtów | Rosnąca |
Obiekt SEQUENCE | Cała baza, z możliwością współdzielenia | 8 bajtów | Rosnąca |
NEWID() — identyfikator GUID | Praktycznie globalny | 16 bajtów | Losowa — powoduje fragmentację indeksu |
NEWSEQUENTIALID() | Praktycznie globalny | 16 bajtów | Rosnąca w obrębie sesji serwera |
Kolumna „kolejność zapisu” ma znaczenie praktyczne: wartości losowe rozrzucają wstawiane wiersze po całym indeksie, co przy dużych tabelach zauważalnie spowalnia zapis.
Wybór centralnego rejestru zamiast identyfikatora GUID ma dwa uzasadnienia. Pierwsze to rozmiar: osiem bajtów zamiast szesnastu, przy setkach milionów wierszy w rejestrach pomocniczych daje różnicę liczoną w gigabajtach. Drugie to kolejność — wartości rosnące trafiają zawsze na koniec indeksu, podczas gdy losowe rozrzucają zapisy po całej strukturze, wymuszając jej ciągłą reorganizację.
Jak korzystać z tabeli w praktyce
Praca z numerami referencyjnymi sprowadza się do kilku zasad, których naruszenie bywa kosztowne:
- Nie zmieniaj numeru przypisanego rekordowi — odwołują się do niego wpisy w historii, blokadach i potwierdzeniach, a żadne z tych powiązań nie jest chronione kluczem obcym.
- Nie ponawiaj wydanych numerów, nawet po usunięciu rekordu; wpisy w rejestrach pomocniczych mogły pozostać i przypisałyby się do nowego obiektu.
- Pobieraj numer w tej samej transakcji, w której powstaje rekord — inaczej przy błędzie zostaje wydana wartość bez właściciela.
- Traktuj luki w numeracji jako normalne; wynikają z wycofanych transakcji i nie wymagają naprawy.
- Nie interpretuj numeru jako informacji biznesowej — nie mówi nic o rodzaju rekordu ani o dacie jego powstania.
- Przy odtwarzaniu bazy z kopii sprawdź stan rejestru, zanim dopuścisz użytkowników do pracy.
Sprawdzenie stanu rejestru: najwyższy wydany numer, liczba wydanych wartości i skala luk w numeracji:
SELECT MAX(REFNO) AS NAJWYZSZY,
MIN(REFNO) AS NAJNIZSZY,
COUNT(*) AS WYDANYCH,
MAX(REFNO) - MIN(REFNO) + 1
- COUNT(*) AS LUK_W_NUMERACJI
FROM dbo._refno;
Luki są zjawiskiem normalnym — powstają przy transakcjach wycofanych po pobraniu numeru. Ich obecność nie świadczy o błędzie i nie wymaga uzupełniania.
Tabela o jednej kolumnie rzadko trafia do dokumentacji, a bywa jednym z ważniejszych elementów bazy. To od niej zależy, czy da się jednym zapytaniem zebrać wszystko, co dotyczy danego dokumentu — jego historię, kto go blokował, kto potwierdził zapoznanie się z nim i gdzie znajduje się powiązany punkt na mapie.
Powiązane tabele i dokumentacja
Numer referencyjny jest wspólnym mianownikiem rejestrów pomocniczych opisanych poniżej: