Nowe posty

Autor Wątek: Jak zaprojektować serwer do gromadzenia dużych ilości dancyh  (Przeczytany 13854 razy)

Offline

  • Users
  • Nowy na forum
  • *
  • Wiadomości: 5
    • Zobacz profil
Cześć

Zastanawiam się w jakim kierunku powinienem pójść projektując pewien serwer do gromadzenia pakietów danych pomiarowych pochodzących z dużej ilości urządzeń pomiarowych.

Załóżmy że pracuje 100000 mierników - nadajników radiowych, każdy o unikanym numerze ID. Jest też 1000 odbiorników radiowych (w otoczeniu każdego jest po 100 nadajników) zbierających dane z tych mierników, które poprzez internet na bieżąco wysyłają do mojego serwera zarejestrowane od nadajników dane. Sprawę komplikuje fakt, że jeden nadajnik może być usłyszany przez 2 odbiorniki, więc do serwera może dotrzeć kilka kopi takiej samej ramki. Z tego powodu zanim zapiszę dane do bazy na serwerze (lub plików) chciałbym je chociaż przez 60 trzymać w pamięci podręcznej; dopiero potem decydowałbym, czy dane zapisać.

Jak najoptymalniej zrealizować to zadanie po stronie serwera? Mój pomysł jest następujący: urządzenie pomiarowe po odebraniu ramki radiowej wysyła do skryptu PHP na moim serwerze żądanie przetworzenia ramki. Skrypt wstępnie sprawdza poprawność ramki po czym przekazuje ją do daemona linuxowego (jeszcze nie wiem w jaki sposób). Daemon akumuluje dane przez 60 w pamięci podręcznej, po czym wykonuje jakieś operacje na nich i zapisuje do odpowiednich plików.

Jak myślicie czy takie podejście jest poprawne? Czy zrobilibyście to inaczej?

Pozdrawiam
Bartek

Offline mateo86

  • Users
  • Guru
  • *****
  • Wiadomości: 652
    • Zobacz profil
Jak zaprojektować serwer do gromadzenia dużych ilości dancyh
« Odpowiedź #1 dnia: 2013-12-09, 11:01:10 »
Hmm... Niewiele wiadomo z tego co napisałeś o nadajnikach i odbiornikach, czy da się je odpowiednio sparować, albo zaprogramować tak, żeby tylko jeden odbiornik odbierał dane z konkretnego miernika.

To co mi przychodzi do głowy i jest w miarę optymalne to, że mając unikalny ID można decydować z którego odbiornika, dane z jakich mierników są zczytywane. Wiesz w takim przypadku, że z odbiornika nr 1 przyjdą dane z mierników nr 1-100, z odbiornika nr 2 będą dane z mierników 101-200 itd. Wtedy nie będziesz musiał przechowywać w pamięci podręcznej danych, które mogą się okazać całkiem pokaźnych rozmiarów i w końcowym efekcie wszystko zapchać.
Nawet samo porównanie ze sobą ramek w takiej liczbie może zająć sporo czasu.

Zastanowiłbym się też, czy php będzie wystarczająco szybkie do sprawdzania poprawności ramek i przekazywania ich dalej do demona i zapisania. Nie wiadomo też z jaką czestotliwością będą odbierane dane, ale sądząc po tym, że chcesz przechowywać dane w pamięci podręcznej przez 60s, to mniemam, że w ciągu minuty chcesz obsłużyć 100000 zapytań - sporo. Nawet bardzo sporo.
Zamiast jednego serwera, postawiłbym kilka pośredniczących i synchronizujących co jakiś czas już zweryfikowane dane z jednym głównym.

Offline

  • Users
  • Nowy na forum
  • *
  • Wiadomości: 5
    • Zobacz profil
Jak zaprojektować serwer do gromadzenia dużych ilości dancyh
« Odpowiedź #2 dnia: 2013-12-09, 11:41:21 »
Każdy z nadajników będzie wysyłał po 60 bajtów co 180s. Odbiornik może zgromadzić kilka ramek i wysyłać je w interwale np. co 3min do serwera, czyli 33kB/s.

Przy 1000 odbiorników daje to 3 zapytania/s. W skrypcie PHP chcę tylko sprawdzić, czy rozmiary ramek danych się zgadzają z nagłówkiem, to nie będzie skomplikowane

Jak system zacznie się rozrastać to zapytań będzie więcej, bo wiecej będzie odbiorników i nadajników. Przy moich aktualnych założeniach sprawa nie wygląda skomplikoawnie (3 zapytania/s, każde zapytanie z danymi o rozmiarze ok. 6kB), ale chciałbym żeby moje rozwiązanie było skalowalne i mogło w przyszłości obsłużyć dużo większą liczbę nadajników i odbiorników. Z tego powodu pomysł z kilkoma serwerami pośredniczącymi jest całkiem ciekawy. Na razie jednak chcę wykorzystać jeden serwer.

Może nie jest to tera istotne ale zapomniałem dodać, że z serwerem będą się także komunikowały aplikacje kliencie, które będą chciały co jakiś czas pobrać część zmagazynowanych danych.

Offline Piotr Chmura

  • Administrator
  • Guru
  • *****
  • Wiadomości: 5060
    • Zobacz profil
Jak zaprojektować serwer do gromadzenia dużych ilości dancyh
« Odpowiedź #3 dnia: 2013-12-09, 14:10:26 »
Przychodzi jakiś identyfikator odczytu (np czas) ?
Jeśli tak, to nie widzę sensu trzymania danych w pamięci przez tą minutę. Od razu zapis do bazy po kluczu id_miernika, id_odczytu.

Offline

  • Users
  • Nowy na forum
  • *
  • Wiadomości: 5
    • Zobacz profil
Jak zaprojektować serwer do gromadzenia dużych ilości dancyh
« Odpowiedź #4 dnia: 2013-12-09, 15:44:25 »
Sprawa nie jest taka prosta. Odbiorniki kiedy nie mają kontaktu z serwerem, zapisują ramki odebrane od nadajników do swojej wewnętrznej pamięci flash. Następnie jak już odbiornik uzyska połączenie, to wysyła zebrane dane do serwera. Oczywiście każda odebrana ramka posiada znacznik czasu (nadany przez odbiornik w momencie odbioru), ale odbiornik może z opóźnieniem wysłać je do bazy - czasami nawet kilkudniowym. Jest to jeden z argumentów dla których nie chciałem do akumulowania ramek używać bazy danych, lecz osobnych plików na serwerze dla każdego urządzenia. Rozmiar każdego z plików będzie 100.000 razy mniejszy niż rozmiar jednej bazy danych, wiec łatwiej będzie ni także dane posortować. Poza tym dane na serwerze chciałbym składować przez min. 3 lata z każdego urządzenia, 60B/180 na nadajnik * 100.000 nadajników * 3 lata = 3TB danych. Zamiast przeszukiwać całą taką bazę aby znaleźć dane z czujnika o numerze 0x12345678 i to z jakiegoś konkretnego przedziału czasu, wolę otworzyć plik tego urządzenia i go odczytać.

Offline

  • Users
  • Nowy na forum
  • *
  • Wiadomości: 3
    • Zobacz profil
Jak zaprojektować serwer do gromadzenia dużych ilości dancyh
« Odpowiedź #5 dnia: 2013-12-09, 18:01:16 »
Moim zdaniem dane powinny być zapisywane w bazie dlaczego:
- łatwy backup
- łatwy dostęp do informacji (skoro masz unikatowe ID odbiorników możesz budować dowolnie kwerendy; odczyty, statystyki, porównania itd. itp)
- skoro masz timestamp (możesz dodatatkowo założyć - ts - odczyt z odbiornika, ts - dodania do bazy) - możesz przerzucać dane dowolnie na inny klaster, załóżmy co miesiąc przerzucasz dane starsze za pomocą funkcji/skryptu
- łatwość napisania w php/pythonie obrabiającego dane
Bardziej obawiałbym się o kolejkowanie na wejściu serwera.

Offline Piotr Chmura

  • Administrator
  • Guru
  • *****
  • Wiadomości: 5060
    • Zobacz profil
Jak zaprojektować serwer do gromadzenia dużych ilości dancyh
« Odpowiedź #6 dnia: 2013-12-10, 08:10:03 »
Cytat: mr.bartek96
Oczywiście każda odebrana ramka posiada znacznik czasu (nadany przez odbiornik w momencie odbioru), ale odbiornik może z opóźnieniem wysłać je do bazy - czasami nawet kilkudniowym.
Tym bardziej nie widzę sensu buforowania danych na czas 1 minuty... Tym bardziej, że odczyty z tego samego pomiaru trafiające przez 2 różne odbiorniki będą miały inny znacznik (ts), więc raczej nie stwierdzisz, że to ten sam odczyt.

Miejsce jest obecnie tanie... co to są 3TB w ciągu 3 lat ?
Będę się upierał przy bazie danych ;-)

Offline

  • Users
  • Nowy na forum
  • *
  • Wiadomości: 5
    • Zobacz profil
Jak zaprojektować serwer do gromadzenia dużych ilości dancyh
« Odpowiedź #7 dnia: 2013-12-10, 13:10:53 »
Znacznik czasu dla tej samej ramki odebranej przez różne odbiorniki może różnić się max. o parę sekund, mimo że pierwszy odbiornik wyśle dane do serwera natychmiast, a drugi po np. 8 godzinach. Natomiast treść ramki nie uwzględniając różnicy w znaczniku czasu, będzie identyczna. Dodatkowo w każdej ramce są informacje nadmiarowe gwarantujące, że jeden nadajnik nigdy nie wyśle 2 identycznych ramek.
Jest jeszcze jeden argument, który obniża przydatność bazy danych: dane w ramkach nadajników są szyfrowane. Załóżmy że nadajniki mierzą napięcie. Ponieważ treść ramek jest szyfrowana, to nie będę w stanie stworzyć kwerendy, która zwróci mi ramki posortowane według tego napięcia.
Z kolei buforowanie ramek może być przydatne nawet, jeśli ramki będą zapisywane w bazie. Kiedy nie mam bufora, to muszę najpierw zadać pytanie do bazy, czy znajduje się w niej ramka o konkretnej treści, a jeśli jej tam nie znajdę, to wtedy dodaję nowy rekord. Mając 60 pamięci podręcznej na ramki mogę szybciej zdecydować, czy ramkę zapisać, czy nie.
Poza tym ta skalowalność... Teraz zakładam 100.000 nadajników, ale jak będzie ich 10.000.000? I do tego minimalny interwał wykonywania pomiaru może być równy 15? Dla urządzeń nadających dane tak często mogę zmniejszyć okres przechowywania danych do np. 6 miesięcy, ale i tak ilość danych będzie przeogromna. Dodatkowo dane trzeba zabezpieczyć przed utratą stosując macierze RAID.

A jeśli chodzi o backup to przy zapisie danych do pliku też wydaje mi się to sprawą nieskomplikowaną - kopiuję cały folder z plikami w inne miejsce i po robocie.

Offline Paweł Kraszewski

  • Administrator
  • Guru
  • *****
  • Wiadomości: 2503
  • Lenistwo jest matką potrzeby = babcią wynalazku
    • Zobacz profil
    • Linuxpedia.PL
Jak zaprojektować serwer do gromadzenia dużych ilości dancyh
« Odpowiedź #8 dnia: 2013-12-10, 14:21:52 »
Cytat: mr.bartek96
Jest jeszcze jeden argument, który obniża przydatność bazy danych: dane w ramkach nadajników są szyfrowane. Załóżmy że nadajniki mierzą napięcie. Ponieważ treść ramek jest szyfrowana, to nie będę w stanie stworzyć kwerendy, która zwróci mi ramki posortowane według tego napięcia.
Ja pitolę, nie sącz tak istotnych danych.

Znacznik czasu kto "wymyśla"? Miernik? Nadajnik? Odbiornik?
Kto szyfruje ramkę?  Miernik? Nadajnik? Odbiornik?
Czy znacznik czasu jest zaszyfrowany?
Czy ID nadajnika jest zaszyfrowany?
Jakie dane per-rekord oprócz zaszyfrowanej ramki chcesz zrzucać do bazy?
Jakie operacje chcesz robić później na bazie? Według jakich kryteriów wyszukiwania?
Jaki będzie % odczytów do zapisów w bazie?
Czy ramki/rekordy mają stały rozmiar? Duży? Mały?
Co jest gorsze w tym systemie - zgubienie czy duplikacja wpisu?
Piszesz o retencji danych. Czym wywołanej? Rozmiarem? Czasem?

Jak chcesz, żeby ktoś pomógł, to daj też jakieś użytecznie informacje od siebie. Wróżki mają świąteczny urlop i są w Laponii u Czerwonego.
Paweł Kraszewski
~Gentoo/FreeBSD/OpenBSD/Specjalizowane customy

Offline mateo86

  • Users
  • Guru
  • *****
  • Wiadomości: 652
    • Zobacz profil
Jak zaprojektować serwer do gromadzenia dużych ilości dancyh
« Odpowiedź #9 dnia: 2013-12-10, 15:25:23 »
Jeśli czas między nadajnikami zawierającymi tą samą ramkę może wynieść do 8 godzin, to również nie widzę sensu przechowywać tych danych w pamięci podręcznej przez minutę. Może się zdarzy, a może nie, że wychwycisz powtarzające się w tym czasie ramki.
A jeśli przeskalujesz to do 10.000.000 urządzeń, wtedy na 100% wszystko się zapcha. Weź przykład z CERN'u - zobacz jak oni zarządzają danymi z detektorów - a mają ich na prawdę sporo. Oni najpierw wstępnie sprawdzają poprawność, po czym zapisują i dopiero po jakimś czasie analizują wyniki i robią dalszą obróbkę danych. Nic nie buforują, bo po prostu by to się wszystko zapchało i szlag wszystkie eksperymenty by trafił.

Ogólnie to z każdym postem podajesz coraz więcej informacji i doszukujesz się problemów tam, gdzie raczej nie wystąpią. Obstajesz przy tym buforowaniu, które według tego co do tej pory nam powiedziałeś nie jest do niczego potrzebne. Teraz wiemy, że ramka będzie szyfrowana. A czy trzeba zapisywać zaszyfrowane dane? Czy nie mogą one być zdekodowane po przesłaniu? Ułatwi to Ci życie później i zarządzanie tymi danymi będzie szybsze i mniej problemowe.
I chmoorek dobrze radzi, ze lepiej wykorzystać bazę danych - wszystkie dane będą spójne, a i dostęp do bazy danych jest znacznie szybszy niż do milionów, jak nie miliardów plików na dysku. Nie wiem czy wiesz, ale systemy plików pozwalają na ograniczoną ilość plików na dysku, choć jest to liczba bardzo duża.

Opisz dokładnie czego oczekujesz od tego rozwiązania i przedstaw wszystkie problemy i komplikacje, które przewidujesz.

Offline

  • Users
  • Nowy na forum
  • *
  • Wiadomości: 5
    • Zobacz profil
Jak zaprojektować serwer do gromadzenia dużych ilości dancyh
« Odpowiedź #10 dnia: 2013-12-10, 19:27:51 »
Miernik = nadajnik. mierzy jakieś wartości, szyfruje je i wysyła w ramce radiowej, która ma postać:

01020F0ExxXXxxXXxxXXxxXX

gdzie
01020F0E to 4-bajtowy unikalny numer ID nadajnika
xxxxxxxxxxx - zaszyfrowany przez nadajnik pakiet danych, konkretny nadajnik nadaje zawsze pakiet danych o takiej samej długości. Przeważnie rozmiar tego pola będzie między 20 - 100 bajtów - zależy od typu miernika/nadajnika.

Odbiornik nasłuchuje w odpowiednim paśmie radiowym, jak odbierze jakąś ramkę to dokleja do niej swój czas UTC kiedy usłyszał ramkę, np. 520234DC. Jeśli ma połączenie z serwerem to przesyła tą ramkę do serwera, wtedy ramka ma postać
 
520234DC01020F0ExxXXxxXXxxXXxxXX

Ramka ta trafia do serwera i jest przekazywana do demona. Ten sprawdza, czy w buforze znajduje się już ramka o treści 01020F0ExxXXxxXXxxXXxxXX. Jeśli tak, to nie zapisuję nowej ramki do bufora, jeśli nie - to ją zapisuję dodając do niej tymczasowo czas serwera. Daemon cyklicznie przegląda bufor, jak stwierdzi że jakaś ramka znajduje się tam dłużej niż 60, to przystępuje do jej zarchiwizowania.

Mogę całą ramkę zapisać jako rekord do tabeli w bazie, oddzielając od siebie czas UTC, numer ID nadajnika i zaszyfrowane dane.
Ja jednak chcę taką ramkę dopisać do pliku w katalogu

/01/02/0F/0E/5202xxxx.dat

do tego pliku dopiszę linię: 34DCxxXXxxXXxxXXxxXX, czyli oszczędzam 6 bajtów, 4 bajty bo uciąłem numer ID nadajnika i 2 bajty ucięte z czasu UTC.
Kolejne ramki będą zapisywane do plików

/01/02/0F/0E/5202xxxx.dat
/01/02/0F/0E/5203xxxx.dat
/01/02/0F/0E/5204xxxx.dat

każdy plik tworzony co 65535, czyli ok. 18[h].

Daemon trzymający dane w buforze powinien też sygnalizować próbę sabotażu systemu. Nadajniki radiowe nadają ramkę, której część jest jawna. Intruz ze swoim odbiornikiem może podsłuchać urządzenie 01020F0E, dowiedzieć się że pole danych tego urządzenia ma długość 8 bajtów, po czym zacznie nadawać spreparowane ramki 01020F0EyyYYyyYYyyYYyyYY. Jak tą sytuacje obsłużyć - jeszcze nie wiem.

Idąc dalej
Nie mam mam możliwości zdekodowania danych xxXXxxXXxxXX, ponieważ użytkownik nie udostępnił mi klucza do zdekodowania danych od konkretnego urządzenia. Użytkownik może jednak poprosić serwer o przesłanie ramek, które nadało urządzenie 01020F0E w przedziale czasu np. od 52000000 do 520FFFFF. Serwer odpowiada przesyłając użytkownikowi pliki

/01/02/0F/0E/5200xxxx.dat
/01/02/0F/0E/5201xxxx.dat
...............
/01/02/0F/0E/520Fxxxx.dat

Znając klucz AES urządzenia 01020F0E użytkownik może zdekodować dane i np. narysować wykres prezentujący zmiany napięcia w tym czasie.

mateo86:
przy 10.000.000 urządzeń, zakładając że każde nadaje co 3[min], w buforze znaleźć się może max 55555 ramek po około 30 bajtów, co daje tablicę o rozmiarze 1.6MB , więc nic się nie zapcha:) to niewiele. Jeśli okaże się ze urządzeń będzie 2 razy więcej, postawię 2 serwery: jeden będzie obsługiwał urządzenia o ID parzystych, drugi nieparzyste. Jeśli urządzeń będzie 16 razy więcej postawię więcej serwerów i każdy będzie obsługiwał inną pulę urządzeń.

Co do ograniczenia ilości plików na dysku: nie znalazłem nigdzie informacji żeby ta liczba była jakoś ograniczona. Przeprowadzę eksperyment na EXT3, zrobię prosty programik który zapełni mi dysk plikami poukładanymi w strukturze katalogów, którą zaproponowałem i się przekonamy. W każdym katalogu będzie po 256 podkatalogów, a w katalogach najniższych po 2433 pliki (jeden plik na 18godzin przez 5lat).

Podsumowując:
Moim celem jest stworzenie jak najszybszego serwera do składowania i udostępniania danych, bez wyszukanej obróbki - głównie wyszukiwanie danych dla urządzenia po znaczniku czasu. Ja rozumiem że użycie bazy danych jest rozwiązaniem prostym, tylko czy optymalnym? Jeżeli większym nakładem pracy da się to zrobić optymalniej, to poświęcę swój czas.

Użycie daemona jako pośrednika między skryptem PHP a magazynem danych też wydaje mi się dobrym pomysłem, ponieważ po przekazaniu ramki daemonowi skrypt może od razu wysłać potwierdzenie odebrania ramki i zakończyć swoje działanie.

Skłaniam się ku wykorzystaniu systemu zapisu do plików z innego powodu. Na bazie doświadczeń z tworzeniem takiego serwera chciałbym także pójść ze skalą w dół tworząc wersje takich serwerów na systemy wbudowane, bazujące np. na platformie ARM, służące do lokalnego gromadzenia danych (już zdeszyfrowanych).

Mam nadzieję że system opisałem dosyć precyzyjnie. Moim problemem jest to, że nie mam wieloletniego doświadczenia w tym systemie operacyjnym. Nie chcę zabrnąć w ślepy zaułek, pytam się więc bardziej doświadczonych wymiataczy.

Czy przy takiej charakterystyce ramek radiowych i zadaniach postawionych serwerowi nadal twierdzicie, że baza danych jest lepszym rozwiązaniem? Czy jednak zapis do systemu plików?

Offline Paweł Kraszewski

  • Administrator
  • Guru
  • *****
  • Wiadomości: 2503
  • Lenistwo jest matką potrzeby = babcią wynalazku
    • Zobacz profil
    • Linuxpedia.PL
Jak zaprojektować serwer do gromadzenia dużych ilości dancyh
« Odpowiedź #11 dnia: 2013-12-10, 22:44:58 »
O,  no.  Teraz lepiej.

Czy odbiorniki mają synchronizowane zegary? Tj jak dwa zobaczą tą samą ramkę to czy nabiją ten sam czas? No powiedzmy +- 1s, jak ramka trafi na granicę.

Jezt już za późno na wnikliwą analizę, ale tak na szybko :
* jako bufor pośredni prawdopodobnie doskonale nadał by się memcached.
* jako składnica ostateczna pasowaloby jakieś rozwiązanie z rodziny NoSQL,  pewnie najlepiej coś typu bigtable. Ja ostatnio pracuję nad MongoDB -  całkiem fajnie nadaje się do takich zabaw.

Jak odbiorniki się synchronizują zegarem i nadajnik nie nadaje częściej niż co sekundę, to mozna założyć, że para id-stamp jest unikalna i ramka z taką samą parą to duplikat (wtedy bedzie też taki sam payload). Mozna wtedy w bazie zrobic klucz unique (id, stamp) i serwer sam odrzuci duplikaty.
Paweł Kraszewski
~Gentoo/FreeBSD/OpenBSD/Specjalizowane customy

Offline mateo86

  • Users
  • Guru
  • *****
  • Wiadomości: 652
    • Zobacz profil
Jak zaprojektować serwer do gromadzenia dużych ilości dancyh
« Odpowiedź #12 dnia: 2013-12-11, 09:52:25 »
Cytat: mr.bartek96
Co do ograniczenia ilości plików na dysku: nie znalazłem nigdzie informacji żeby ta liczba była jakoś ograniczona. Przeprowadzę eksperyment na EXT3, zrobię prosty programik który zapełni mi dysk plikami poukładanymi w strukturze katalogów, którą zaproponowałem i się przekonamy. W każdym katalogu będzie po 256 podkatalogów, a w katalogach najniższych po 2433 pliki (jeden plik na 18godzin przez 5lat).
Każdy system plików ma ograniczenia tego typu, nigdzie nie stworzysz nieskończenie wiele plików.

http://stackoverflow.com/questions/466521/how-many-files-in-a-directory-is-too-many

EXT3 ma to do siebie, że przy małych rozmiarach partycji (<10GB) maksymalna liczba plików jest dość małą liczbą, wręcz bardzo małą.

Offline Paweł Kraszewski

  • Administrator
  • Guru
  • *****
  • Wiadomości: 2503
  • Lenistwo jest matką potrzeby = babcią wynalazku
    • Zobacz profil
    • Linuxpedia.PL
Jak zaprojektować serwer do gromadzenia dużych ilości dancyh
« Odpowiedź #13 dnia: 2013-12-11, 18:52:03 »
Biorąc pod uwagę, że 1 plik i 1 katalog zużywają po 1 inode, jako limit górny sumy ilości plików i katalogów możesz przyjąć tak heurystycznie dla bezpieczeństwa np 95% dostępnej liczby inodów.
Paweł Kraszewski
~Gentoo/FreeBSD/OpenBSD/Specjalizowane customy

Offline

  • Users
  • Nowy na forum
  • *
  • Wiadomości: 3
    • Zobacz profil
Jak zaprojektować serwer do gromadzenia dużych ilości dancyh
« Odpowiedź #14 dnia: 2013-12-11, 20:36:18 »
Nie wiem, sposób rozwiązywania tegoż problemu jest dziwny.
Buduje się bazę danych za wszelką cenę broniąc się przed użyciem narzędzi do tego służących. Nawet jeśli powstaje jakaś nadmiarowość danych, to rekompensuje ją prostota późniejszej obsługi.
3Tb, co to jest... jedna tabela w postgresie może mieć 32Tb.
Prócz tego jako bufor, też możesz użyć bazę, by później łatwo usunąć duplikaty rekordów.

http://stackoverflow.com/questions/1746213/how-to-delete-duplicate-entries