Pracujemy nad aplikacją internetową, która nie jest jeszcze dostępna dla użytkowników. Mój szef zauważył, że nowo utworzone rekordy mają identyfikator ponad 10 000, mimo że w tabeli mamy tylko mniej niż 100 rekordów. Zakłada, że interfejs sieciowy z jakiegoś powodu tworzy ponad 100 razy więcej tymczasowych rekordów niż rzeczywiste (i usuwa je), i że może to doprowadzić nas do wyczerpania zasięgu w ciągu kilku miesięcy od wydania.
Nie sądzę, żeby miała rację co do przyczyny inflacji tożsamości (kolega, który może odpowiedzieć na to, jest na wakacjach, więc nie wiemy tego na pewno), ale załóżmy, że tak. Powiedziała, że nie chciałaby używać kolumny bigint i że chciałaby, abyśmy przestali automatycznie zwiększać kolumnę identyfikatora i napisali kod po stronie serwera, który wybiera pierwszą „nieużywaną” liczbę całkowitą i używa jej jako identyfikatora.
Jestem studentem informatyki z niewielkim praktycznym doświadczeniem, pełniąc rolę młodszego programisty. Ma wieloletnie doświadczenie w zarządzaniu wszystkimi bazami danych naszej organizacji i projektowaniu większości z nich. I pomyśleć , że jest niepoprawna w tym przypadku, że bigint Identyfikator ma się czego bać i że naśladując funkcjonalność DBMS pachnie o antywzorzec projektowy. Ale jeszcze nie ufam mojemu osądowi.
Jakie są argumenty za i przeciw każdej pozycji? Jakie złe rzeczy mogą się zdarzyć, jeśli użyjemy biginta i jakie są niebezpieczeństwa związane z ponownym opracowaniem funkcji automatycznego zwiększania kół ? Czy istnieje trzecie rozwiązanie, które jest lepsze od któregoś z nich? Jakie mogą być jej powody, dla których warto unikać inflacji wartości nominalnych? Chciałbym usłyszeć również o pragmatycznych powodach - może identyfikatory bigint działają teoretycznie, ale powodują bóle głowy w praktyce?
Aplikacja nie powinna obsługiwać bardzo dużych ilości danych. Wątpię, czy w ciągu najbliższych kilku lat osiągnie 10 000 faktycznych rekordów.
Jeśli robi to jakąkolwiek różnicę, korzystamy z serwera Microsoft SQL. Aplikacja jest napisana w języku C # i używa Linq do SQL.
Aktualizacja
Dziękuję, uznałem istniejące odpowiedzi i komentarze za interesujące. Ale obawiam się, że źle zrozumiałeś moje pytanie, więc zawierają one to, co chciałem wiedzieć.
Tak naprawdę nie martwię się prawdziwym powodem wysokich ID. Jeśli sami nie możemy tego znaleźć, mogę zadać inne pytanie. W tym przypadku interesuje mnie zrozumienie procesu decyzyjnego. W tym celu należy założyć, że aplikacja będzie zapisywać 1000 rekordów dziennie, a następnie usunie ich 9999 . Jestem prawie pewien, że tak nie jest, ale tak właśnie uwierzył mój szef, kiedy poprosiła. Więc w tych hipotetycznych okolicznościach, jakie byłyby zalety i wady używania biginta lub pisania własnego kodu, który przypisuje identyfikatory (w sposób, który ponownie wykorzystuje identyfikatory już usuniętych rekordów, aby upewnić się, że nie ma luk)?
Jeśli chodzi o faktyczny powód, mocno podejrzewam, że dzieje się tak, ponieważ kiedyś napisaliśmy kod do importowania danych z innej bazy danych, co jest dowodem na to, że późniejszą migrację można wykonać w pewnym stopniu. Myślę, że mój kolega faktycznie utworzył kilka tysięcy rekordów podczas importu, a później je usunął. Muszę potwierdzić, czy rzeczywiście tak było, ale jeśli tak, to nie ma nawet potrzeby działania.
źródło
Odpowiedzi:
Nie widząc kodu, trudno jest jednoznacznie powiedzieć, co się dzieje. Chociaż najprawdopodobniej
IDENTITY
wartość jest buforowana, co powoduje luki w wartości po ponownym uruchomieniu programu SQL Server. Zobacz /programming/17587094/identity-column-value-suddenly-jumps-to-1001-in-sql-server, aby uzyskać dobre odpowiedzi i informacje na ten temat.Proste
INT
pole może zawierać wartości do 2 147 483 647. Możesz faktycznie rozpocząć wartość tożsamości od -2 147 483 648, dając pełne 32 bity wartości. 4 miliardy różnych wartości. Wątpię, czy zabraknie ci wartości do użycia. Zakładając, że aplikacja jest czasochłonne 1000 rzeczywistej wartości dla każdego wiersza dodaje, że trzeba być stworzenie prawie 12.000 wierszy dziennie codziennie zabraknie identyfikatorów w ciągu 6 miesięcy zakładając rozpocząłIDENTITY
wartości na 0, i używali wew. Jeśli używałeś BIGINT, musiałbyś poczekać 21 milionów stuleci, zanim zabraknie Ci wartości, jeśli zapisałeś 12 000 wierszy dziennie, zużywając 1000 „wartości” na wiersz.Powiedziawszy to wszystko, jeśli chcesz użyć
BIGINT
jako typu danych pola tożsamości, z pewnością nie ma w tym nic złego. Zapewni to nieograniczoną podaż wartości do wszystkich celów i celów. Różnica w wydajności między INT a BIGINT praktycznie nie występuje na nowoczesnym 64-bitowym sprzęcie i jest znacznie lepsza niż na przykład używanieNEWID()
do generowania identyfikatorów GUID.Jeśli chcesz zarządzać własnymi wartościami dla kolumny identyfikatora, możesz utworzyć tabelę kluczy i zapewnić dość kuloodporny sposób, korzystając z jednej z metod przedstawionych w odpowiedziach na to pytanie: Obsługa jednoczesnego dostępu do tabeli kluczy bez zakleszczenia w programie SQL Server
Inną opcją, przy założeniu, że używasz programu SQL Server 2012+, byłoby użycie
SEQUENCE
obiektu w celu uzyskania wartości identyfikatora dla kolumny. Należy jednak skonfigurować sekwencję, aby nie buforować wartości. Na przykład:W odpowiedzi na negatywne postrzeganie przez szefa „wysokich” liczb, powiedziałbym, jaką to robi różnicę? Zakładając, że używasz
INT
pola, ze związkiemIDENTITY
, w rzeczywistości można rozpocząćIDENTITY
na2147483647
i „przyrost” przez wartość-1
. Nie miałoby to absolutnie żadnej różnicy w zużyciu pamięci, wydajności lub używanym miejscu na dysku, ponieważ liczba 32-bitowa to 4 bajty, bez względu na to, czy jest0
lub2147483647
.0
binarny jest00000000000000000000000000000000
przechowywany w 32-bitowymINT
polu ze znakiem .2147483647
jest01111111111111111111111111111111
- obie liczby zajmują dokładnie taką samą ilość miejsca, zarówno w pamięci, jak i na dysku, i obie wymagają dokładnie takiej samej ilości operacji procesora do przetworzenia. O wiele ważniejsze jest prawidłowe zaprojektowanie kodu aplikacji niż obsesja na punkcie faktycznej liczby przechowywanej w polu klucza.Zapytałeś o zalety i wady: (a) używając kolumny identyfikatora o większej pojemności, takiej jak a
BIGINT
, lub (b) krocząc własnym rozwiązaniem, aby uniknąć luk identyfikacyjnych. Aby odpowiedzieć na te obawy:BIGINT
zamiastINT
jako typ danych dla danej kolumny. Użycie aBIGINT
wymaga podwójnej ilości pamięci, zarówno na dysku, jak i w pamięci dla samej kolumny. Jeśli kolumna jest indeksem klucza podstawowego dla danej tabeli, każdy indeks nieklastrowy dołączony do tabeli będzie również przechowywaćBIGINT
wartość, dwukrotnie większą niżINT
, zarówno w pamięci, jak i na dysku. SQL Server przechowuje dane na dysku na stronach 8 KB, gdzie liczba „wierszy” na „stronę” zależy od „szerokości” każdego wiersza. Na przykład, jeśli masz tabelę z 10 kolumnami, każda z nichINT
, możesz w przybliżeniu przechowywać 160 wierszy na stronie. Jeśli zamiast tych kolumnBIGINT
kolumny, możesz przechowywać tylko 80 wierszy na stronie. W przypadku tabeli z bardzo dużą liczbą wierszy oznacza to wyraźnie, że we / wy wymagane do odczytu i zapisu będzie w tym przykładzie podwojone dla dowolnej liczby wierszy. To prawda, jest to dość ekstremalny przykład - jeśli miał wiersz składający się z jednejINT
lubBIGINT
kolumny i pojedynczejNCHAR(4000)
kolumny, byłbyś (upraszczając) uzyskanie pojedynczy wiersz na stronie, czy stosuje sięINT
lubBIGINT
. W tym scenariuszu nie zrobiłoby to znaczącej różnicy.Opracowanie własnego scenariusza, aby zapobiec lukom w kolumnie identyfikatora. Musisz napisać kod w taki sposób, aby określenie „następnej” wartości identyfikatora do użycia nie kolidowało z innymi działaniami mającymi miejsce w tabeli.
SELECT TOP(1) [ID] FROM [schema].[table]
Przychodzi mi na myśl coś naiwnego. Co jeśli wielu aktorów próbuje jednocześnie zapisywać nowe wiersze w tabeli? Dwóch aktorów może łatwo uzyskać tę samą wartość, co powoduje konflikt zapisu. Obejście tego problemu wymaga szeregowania dostępu do tabeli, co zmniejsza wydajność. Napisano wiele artykułów na temat tego problemu; Pozostawię czytelnikowi przeprowadzenie wyszukiwania na ten temat.Wniosek jest następujący: musisz zrozumieć swoje wymagania i odpowiednio oszacować zarówno liczbę wierszy, jak i szerokość wiersza, a także wymagania dotyczące współbieżności aplikacji. Jak zwykle It Depends ™.
źródło
bigint
będzie prawdopodobnie podziękować sobie za decyzje, które z wyprzedzeniem zamiast konieczności dodać to do tabeli z miliardów wierszy.Głównym zadaniem do wykonania jest znalezienie przyczyny, dla której aktualna wartość jest tak wysoka.
Najbardziej rozsądnym wyjaśnieniem dla wersji SQL Server wcześniejszych niż SQL2012 - zakładając, że mówisz o testowej bazie danych - byłby test obciążenia, po którym następuje czyszczenie.
Począwszy od SQL2012 najbardziej prawdopodobnym powodem jest kilka restartów silnika SQL (jak wyjaśniono w pierwszym podanym linku Max).
Jeśli luka jest spowodowana przez scenariusz testowy, z mojego punktu widzenia nie ma powodu do zmartwień. Ale żeby być bezpiecznym, sprawdziłbym wartości tożsamości podczas normalnego użytkowania aplikacji, a także przed i po ponownym uruchomieniu silnika.
„Zabawne” jest to, że MS twierdzi, że obie alternatywy (flaga śledzenia 272 lub nowy obiekt SEQUENCE) mogą wpływać na wydajność.
To może być najlepsze rozwiązanie, aby użyć BIGINT zamiast INT tylko po to, aby być po bezpiecznej stronie, aby objąć MS następnych „ulepszeń” ...
źródło
Rumtscho, jeśli tworzysz tylko 1000 wierszy dziennie, nie ma wiele do wyboru - użyj typu danych INT z polem Tożsamość i gotowe. Prosta matematyka mówi, że jeśli dasz swojej aplikacji 30-letni cykl życia (mało prawdopodobne), możesz mieć 200 000 wierszy dziennie i nadal znajdować się w dodatnim zakresie liczbowym typu danych INT.
Używanie BigInt jest w twoim przypadku przesadą, może również powodować problemy, jeśli twoja aplikacja lub dane będą dostępne przez ODBC (takie jak wprowadzone do Excela lub MS Access itp.), Bigint nie tłumaczy dobrze przez większość sterowników ODBC do aplikacji komputerowych.
Jeśli chodzi o GUIDY, oprócz dodatkowego miejsca na dysku i dodatkowego wejścia / wyjścia, istnieje ogromny problem polegający na tym, że z założenia nie są one sekwencyjne, więc jeśli są częścią posortowanego indeksu, możesz zgadywać, że każda wstawka będzie wymagają zastosowania indeksu. - Jim
źródło
Czy jest różnica między zastosowanymi wartościami? Czy wartości początkowe wynoszą 10.000 i od tego czasu wszyscy dodają 1? Czasami, jeśli liczba zostanie podana klientom, początkowa liczba jest większa od zera, powiedzmy na przykład 1500, więc klient nie zdaje sobie sprawy, że system jest „nowy”.
Wadą używania biginta zamiast smallinta jest to, że ponieważ bigint wykorzystuje „więcej miejsca na dysku”, podczas odczytu dysku odczytujesz mniej bloków dysku dla każdego dysku. Jeśli przestrzeń wierszy jest niewielka, może to być wadą, jeśli nie, nie ma to większego znaczenia. Również nie ma większego znaczenia, jeśli nie pytasz o wiele zasobów jednocześnie i masz odpowiednie indeksy.
I jak powiedziano w innej odpowiedzi, jeśli martwisz się wyczerpaniem indeksów, nie powinieneś się martwić, smallint poradzi sobie, chyba że masz firmę milionera. Opracowanie mechanizmu „odzyskiwania identyfikatorów” jest kosztowne i dodaje oprogramowaniu punkty awarii i złożoność.
pozdrowienia
źródło
Gdybym był twoim szefem I byłoby być najbardziej zainteresowani powodów dla nieoczekiwanie wysokich wartościach Id ... tak jak ja to widzę, dla każdego z dwóch scenariuszy nakreślonych Państwo:
JEŻELI wcześniejsze testy wykazały podwyższone wartości tożsamości - wtedy twoje inne komentarze na temat oczekiwanej liczby rekordów również zmusiłyby mnie do zasugerowania mniejszego typu klucza. Szczerze mówiąc, zastanowiłbym się również, czy można zresetować sekwencję i przenumerować istniejące rekordy, jeśli test nie jest charakterystyczny dla bieżącego zamierzonego użycia tabeli (większość uważa, że to przesada - „to zależy”).
JEŻELI większość rekordów zapisanych w tabeli zostanie usunięta wkrótce po tym, skłaniam się do rozważenia użycia dwóch tabel; tymczasowa tabela, w której rekordy nie są przechowywane długoterminowo, a druga, w której przechowywane są tylko rekordy, które utworzymy na stałe. Ponownie, twoje oczekiwania dotyczące liczby rekordów długoterminowych sugerują mi użycie mniejszego typu w kluczowej kolumnie, a kilka rekordów dziennie nie spowoduje, że problem z wydajnością spowoduje przeniesienie rekordu z jednej tabeli do drugiej podobnie jeden. Podejrzewam, że to nie jest twój scenariusz, ale wyobraź sobie, że witryna zakupów może preferować utrzymywanie elementu Basket / BasketItem, a kiedy zamówienie zostanie faktycznie złożone, dane zostaną przeniesione do zestawu Order / OrderItem.
Podsumować; Moim zdaniem BIGINTÓW nie należy się obawiać, ale szczerze mówiąc, są one niepotrzebnie duże w wielu scenariuszach. Jeśli tabela nigdy się nie powiększy, nigdy nie uświadomisz sobie, że wybór rodzaju był nadmierny ... ale jeśli masz tabele z milionami wierszy i wieloma kolumnami FK, które są DUŻE, gdy mogłyby być mniejsze - możesz życzyć sobie typy zostały wybrane bardziej zachowawczo (rozważ nie tylko kolumny klucza, ale wszystkie kolumny klucza z przodu i wszystkie kopie zapasowe, które przechowujesz itd.). Miejsce na dysku nie zawsze jest tanie (rozważ dysk SAN w zarządzanych lokalizacjach - tzn. Miejsce na dysku jest wynajmowane).
Zasadniczo opowiadam się za uważnym rozważeniem wyboru rodzaju danych zawsze, a nie czasem . Nie zawsze będziesz poprawnie przewidywał wzorce użytkowania, ale myślę, że podejmiesz lepsze decyzje z reguły, niż zawsze zakładając, że „większe jest lepsze”. Zasadniczo wybieram najmniejszy typ, który może zawierać wymagany i rozsądny zakres wartości i z przyjemnością rozważę INT, SMALLINT, a nawet TINYINT, jeśli uważam, że wartość będzie pasować do tego typu w dającej się przewidzieć przyszłości. Mniejsze typy raczej nie będą używane z kolumnami TOŻSAMOŚĆ, ale mogą z powodzeniem być używane z tabelami odnośników, w których wartości kluczowe są ustawiane ręcznie.
Wreszcie technologie, z których korzystają ludzie, mogą znacząco wpłynąć na ich oczekiwania i odpowiedzi. Niektóre narzędzia częściej powodują luki w zakresach, np. Przez wcześniejsze rezerwowanie zakresów tożsamości na proces. Natomiast @DocSalvager sugeruje dokładną sekwencję podlegającą kontroli, która wydaje się odzwierciedlać punkt widzenia szefa; Osobiście nigdy nie wymagałem takiego poziomu władzy - chociaż ogólna zasada, że tożsamości są sekwencyjne i ogólnie bez luk, często była dla mnie niezwykle przydatna w sytuacjach wsparcia i analizie problemów.
źródło
Używanie
bigint
jako tożsamości i życie z lukami:int
nadal zapewniałoby dane z około 2 milionów dni; więcej stron będzie musiało zostać przeczytanych i napisanych; indeksy mogą być głębsze. (W tych tomach nie jest to jednak istotny problem).Skręć swój własny:
źródło
Jeśli naprawdę zależy ci na przekroczeniu górnego progu INT dla swoich PK, rozważ użycie GUID. Tak, wiem, że to 16 bajtów vs 4 bajty, ale dysk jest tani.
Oto dobry opis zalet i wad.
źródło
Klucze podstawowe RDBMS (kolumna zwykle nazywana „ID”)
Luki nie można uniknąć w kolumnach (polach) autoinkrementacji RDBMS. Są one przede wszystkim przeznaczone do tworzenia unikalnych PK. W celu zwiększenia wydajności główne produkty dzielą je na partie, więc automatyczne mechanizmy odzyskiwania dla różnych usterek normalnej pracy mogą spowodować, że liczby pozostaną nieużywane. To normalne.
Nieprzerwane sekwencje
Gdy potrzebujesz nieprzerwanego numeru sekwencji, takiego, jakiego często oczekują użytkownicy, powinna to być osobna kolumna, która jest przypisana programowo i nie powinna być PK. Zatem te 1000 rekordów może mieć tę samą liczbę w tej kolumnie.
Dlaczego użytkownicy chcą nieprzerwanych sekwencji?
Brakujące numery sekwencyjne są najbardziej podstawowym znakiem błędu wykrytym podczas każdego rodzaju audytu. Ta zasada „Księgowości-101” jest wszechobecna. Jednak to, co działa w przypadku niewielkiej liczby rekordów prowadzonych ręcznie, ma poważny problem, gdy stosuje się je do bardzo dużej liczby rekordów w bazach danych ...
Ponowne użycie kluczowych wartości dla niepowiązanych rekordów unieważnia bazę danych.
Użycie „pierwszej nieużywanej liczby całkowitej” wprowadza prawdopodobieństwo, że w pewnym momencie w przyszłości liczba zostanie ponownie użyta dla rekordów niezwiązanych z oryginałem. To sprawia, że baza danych jest niewiarygodna jako dokładne przedstawienie faktów. Jest to główny powód, dla którego mechanizmy autoinkrementacji są zaprojektowane tak, aby nigdy nie wykorzystywać ponownie wartości.
źródło