2012-03-11 10 views
7

Obecnie pracuję nad prototypem systemu rejestracji. Jest to bardzo uproszczone i zasadniczo jest po prostu formą .NET, która zostaje zapisana w MongoDB.Efektywne generowanie pojedynczych kluczy dla wpisów bazy danych

Co utknąłem jest skutecznym sposobem na wygenerowanie unikalnego identyfikatora/klucza dla każdego użytkownika. Te identyfikatory muszą być przyjazne dla ludzi, więc powinny zawierać ciąg znaków alfanumerycznych o długości 7 znaków, np. A1B2C3X.

Rozwiązania, które do tej pory widziałem, używają prostej funkcji do generowania losowego ciągu znaków, a następnie sprawdzania bazy danych, aby sprawdzić, czy jest ona unikatowa (a jeśli nie, powtórz, dopóki nie znajdziesz unikalnej). To oczywiście będzie coraz bardziej kosztowne obliczeniowo, ponieważ liczba pozycji w bazie danych rośnie.

Mój pomysł polega na wstępnym obliczeniu unikalnego zestawu identyfikatorów i zapisaniu go w innej bazie danych. Następnie, gdy muszę dodać nowy wpis do bazy danych użytkownika, mogę "pop" id z mojego id danych (w stałym czasie) i wiem, że nie istnieje on już w bazie danych użytkownika bez konieczności wyszukiwania go.

Jestem pewna, że ​​ktoś musiał wcześniej coś takiego zrobić. Czy istnieje lepszy sposób? Nie wiem, dlaczego tak bardzo się z tym zmagam. Twój wkład jest bardzo doceniany.

+2

Czy ObjectId, dostarczony przez sterownik MongoDB jest zbyt ludzki nieprzyjazny dla twojego przypadku użycia? –

+0

Chciałem zasugerować, co zasugerował @EkinKoc (a jeśli masz 40 postaci, to jest sposób, aby przejść). Ale jeśli potrzebujesz dokładnie 7 znaków, metoda, którą obrysowujesz, powinna być * mniej kosztowna *, prostsza i mniej podatna na błędy niż posiadanie osobnego pliku kluczy db, aby wyskakiwać wartości. Szansa na kolizję losowego 7-znakowego ciągu alfanumerycznego jest praktycznie zerowa. Jest to rzadki przypadek, którego nie należy optymalizować. (Poza tym tworzenie użytkowników jest rzadkością, kontrola unikalności db jest wystarczająco szybka dla stosunkowo rzadkiego procesu). –

+0

@BenLee: prawdopodobieństwo kolizji zmienia się ze skalą :) –

Odpowiedz

11

Generowanie losowego łańcucha w aplikacji i sprawdzanie, czy jest unikatowe, nie jest złym rozwiązaniem. Nie przejmuj się tym, że jest nieefektywny, nie jest - i zdecydowanie nie porównuje się do alternatyw. Z pewnością będzie to szybsze niż uruchomienie db.user.count() lub zachowanie oddzielnej tabeli z wcześniej obliczonymi identyfikatorami. Po prostu musisz to zrobić dobrze.

Po pierwsze, jak często będą tworzyć nowych użytkowników? Prawdopodobnie niezbyt często w porównaniu do innych rzeczy, więc tak naprawdę cała dyskusja na temat wydajności jest dyskusyjna. Po drugie, z 7 znakami A-Z, 0-9 to zakres 36^7 lub około 78 miliardów. Minie trochę czasu, zanim zaczniesz dostrzegać kolizje.

Jeśli po prostu zrobić to w ten sposób, że nie będzie ponosić żadnych kar wydajności, chyba że istnieje kolizja (co jest bardzo prawdopodobne):

  • Generowanie unikalnego identyfikatora użytkownika
  • WPISAć obiekt użytkownika, przy użyciu identyfikator użytkownika jako wartość: _id
  • Sprawdź, czy nie występują błędy klucza duplikatu (sposób wykonania tego zależy od języka i sterownika, ale może wymagać uruchomienia komendy getLastError).
  • Na duplikatu błędu klucza zacząć od nowa, generując nowy identyfikator użytkownika

W ten sposób nie będzie tylko dodatkowa praca w razie kolizji (a ja naprawdę chcę podkreślić, jak bardzo mało prawdopodobne, że będzie być).

Istnieje inny sposób generowania unikalnego identyfikatora użytkownika: pobranie aktualnego znacznika UNIX (do drugiego), dołączenie skrótu do nazwy hosta, a następnie ID procesu, a na końcu do bieżącej wartości licznika. Jest to w rzeczywistości generowane przez Mongo ObjectId i gwarantuje, że możesz wygenerować tyle obiektów na sekundę, na proces, jako maksymalną wartość twojego licznika (który w Mongo ma 3 bajty, czyli 16 milionów). Zobacz dokumenty na ObjectId, jeśli interesują Cię szczegóły: http://www.mongodb.org/display/DOCS/Object+IDs

Ma właściwość, że twoje identyfikatory użytkownika będą naturalnie sortowane w kolejności tworzenia, ale mają długość 12 bajtów, czyli nieco dłużej niż 7 znaków, Niestety.Możesz użyć tej samej metody i pominąć nazwę hosta/pid i skrócić licznik (który może być również liczbą losową, jeśli chcesz) do dwóch bajtów, wtedy będziesz miał do 6 bajtów, co prawdopodobnie mogłoby być ściśnięte do około 9 znaki AZ, 0-9.

+0

dzięki za szczegółową odpowiedź. Twoje rozwiązanie brzmi jak najprostsze. Teraz warto wstawić za pomocą _id, a następnie sprawdzić błąd klucza duplikatu, zamiast sprawdzać collison ręcznie (w aplikacji), a następnie wstawić. Myślę, że ta subtelna różnica była powodem do obaw o skuteczność rozwiązania, które, jak słusznie zauważysz, nie jest uzasadnione tak długo, jak robisz to poprawnie. Dzięki jeszcze raz. –