Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[MySQL] Znikające dane w tabeli bazy danych

malum 14 Sty 2012 02:14 5853 8
  • #1 14 Sty 2012 02:14
    malum
    Poziom 23  

    Oświećcie mnie co się dzieje, bo już mi sił brakuje.
    Stworzyłem tabelę bazy danych zbudowaną w taki sposób:
    [MySQL] Znikające dane w tabeli bazy danych
    której zadaniem jest przechowywanie informacji o statusie wiadomości.
    Litera P oznacza, że wiadomość została przeczytana, litera U oznacza, że wiadomość została usunięta, a pusta komórka oznacza, że wiadomość nie została odczytana przez adresata. Gdy dodawana jest nowa wiadomość do bazy danych tworzony jest nowy wiersz (rekord) z samymi pustymi komórkami. Gdy natomiast założone zostaje konto dla nowego użytkownika dodawana jest do tabeli bazy danych nowa kolumna, gdzie w nagłówku jako nazwa kolumny wpisany jest numer id użytkownika.
    Cały mechanizm działa na tej zasadzie, że system sprawdza, czy wybrana wiadomość została odczytana lub usunięta przez danego użytkownika.
    Wszystko niby działało poprawnie, ale zaczęły do mnie dochodzić zgłoszenia, że system na niektórych kontach niepoprawnie odczytuje informacje o przeczytaniu i usunięciu wiadomości. Spędziłem kilkanaście godzin na analizowaniu kodu źródłowego strony i nic, nie znalazłem błędu. Stworzyłem więc od zera nowy moduł odczytu wiadomości i problem się powtórzył. Postanowiłem więc sprawdzić czy dane są poprawnie zapisane w bazie MySQL i wszystko wygląda tak jak powinno. Dla przykładu w kolumnie 118 mam 3 wiadomości przeczytane i dwie usunięte, a w 40 i 163 kolumnie 4 wiadomości przeczytane i 2 usunięte. System dla użytkowników 40 i 163 działa prawidłowo, a dla 118 nie. Gdy wyeksportowałem tabelę bazy danych do Excela okazało się, że kolumna 118 jest pusta, nie ma w niej żadnych wartości, pomimo iż w podglądzie bazy danych i w widoku wydruku są. Dana po prostu niby są w bazie danych, ale gdy system próbuje je odczytać to cudownie znikają. Co się dzieje?

    0 8
  • #2 14 Sty 2012 14:01
    marcinj12
    Poziom 40  

    Abstrahując od całej reszty - masz źle przemyślaną i zaprojektowaną bazę danych. Baza danych to nie Excel, gdzie na przecięciu komórek wpisujesz sobie jakieś wartości i wszystko jest jasne i czytelne - dla człowieka. Przy pracy z bazami danych projektuje się tabelę raz, a potem dodaje do niej wiersze. Ilość wierszy w tabeli może iść w dziesiątki milionów, ogranicza je wielkość dysku i czasu potrzebnego na wstawienie / operacje na rekordach. Ilość kolumn powinna być stała, a użytkownik nie powinien mieć uprawnień do modyfikowania struktury bazy danych.
    Tak samo powinno to wyglądać u Ciebie: masz dwie tabele, obrazowo pisząc:
    UŻYTKOWNICY(id_użytkownika, login, hasło) oraz WIADOMOŚCI(id_wiadomości, id_użytkownika, status_wiadomości).
    Jak dochodzi nowy użytkownik - dodajesz rekord do tabeli UŻYTKOWNICY.
    Jak wypuszczasz nową wiadomość - dodajesz 1000 rekordów (czy ile tam masz tych użytkowników) do tabeli WIADOMOŚCI, po jednym rekordzie dla każdego użytkownika.
    Zmieniając status wiadomości odszukujesz w tej tabli id_wiadomości i id_użytkownika i zmieniasz status poleceniem UPDATE.

    Wracając do Twojego problemu - prawdopodobnie przekroczyłeś któryś z limitów bazy MySql co do max. ilości kolumn w tabeli. W linku piszą o nieprzekraczalnej ilości 4096 kolumn dla MyIsam i 1000 dla InnoDb, jednak może być mniejszy zależnie od typu danych w kolumnie. Ewentualnie coś jest nie tak z programową częścią obsługi danych, ale bez kodu nic powiedzieć nie można (nawet nie próbuję sobie wyobrazić, jak wygląda zapytanie SQL'owe dla tysiąca kolumn...).
    Również możliwy jest konflikt, kiedy kilku użytkowników na raz próbuje zmienić status tego samego wiersza - nie wiem jak MySql blokuje rekordy, ale być może bez odpowiedniego mechanizmu lock'a sobie nie radzi z konkurencyjnym updatem na tym samym rekordzie.
    PS. Z bazy danych nic "magicznie" samo z siebie nie ma prawa znikać. Zwykle są to jakieś błędy po stronie aplikacji.

    0
  • #3 14 Sty 2012 15:38
    malum
    Poziom 23  

    Docelowo baza ma zawierać maksymalnie 1000 użytkowników. Kolumna id jest typu integer, natomiast pozostałe kolumny są typu char(1) więc o przepełnienie tabeli chyba nie powinienem się martwić. Zastosowane przeze mnie rozwiązanie jest bardzo praktyczne i łatwe do odczytania. Nie podoba mi się natomiast pomysł z tworzeniem 1000 rekordów po dodaniu każdej nowej wiadomości. W ten sposób tworzonych byłoby wiele niepotrzebnych rekordów, a czytelność tabeli spadłaby praktycznie do zera :(
    Jest jakieś inne rozwiązanie?

    0
  • #4 14 Sty 2012 16:34
    marcinj12
    Poziom 40  

    Ale tabela nie ma służyć jako obiekt do odczytywania danych przez człowieka - ma służyć jako obiekt do przechowywania danych przez komputer.
    Widzę że próbujesz robić "kalkę" z pracy z Excelem na pracę z bazą danych - tylko że to tak nie działa i na dłuższą metę się nie sprawdzi.
    Chyba, że chcesz z nią pracować eksportując za każdym razem całą tabelę do Excela i w nim filtrując dane - ale jaki był by wtedy sens tworzenia tej bazy, jak można było zostać przy Excelu?

    Piszesz, że nie podoba Ci się pomysł tworzenia 1000 rekordów po dodaniu każdej nowej wiadomości - tak z ciekawości, jak często wychodzą takowe, o jakiego rzędu wielkości liczbie tu mówimy?
    Zresztą, czy Ci się to podoba czy nie - tak to się właśnie robi i kropka. :)

    To, czy będziesz miał 1000 kolumn czy 1000 wierszy to niemal jednakowy rozmiar dla bazy, a wrzucenie tego w wiersze umożliwia np. założenie indeksów na kolumnie id_uzytkownika czy statusu, co znacznie przyspiesza wyszukiwanie po tych wartościach. Jeszce raz powtórzę: tabela ma być czytelna dla komputera, nie człowieka.

    Powiedz, w jaki sposób w tej "praktycznej i łatwej do odczytania tabeli" tabeli którą masz teraz, wybierzesz np. ID wszystkich użytkowników, którzy nie przeczytali wiadomości o ID=10, ale przeczytali (bądź usunęli) wiadomość o ID = 9 ? Mówimy o sytuacji kiedy baza już się zapełni 1000 użytkowników i wieloma wiadomościami.
    Bo w przykładzie który podałem, było by to coś w tym stylu:

    Kod: sql
    Zaloguj się, aby zobaczyć kod

    0
  • #5 14 Sty 2012 17:01
    malum
    Poziom 23  

    Masz rację, ale nie ma innego sposobu?

    Dla przykładu nasza-klasa ma pewnie ze 20 mln użytkowników, każdy wysyła wiadomości, to jak mam rozumieć po każdym wysłaniu wiadomości do bazy danych dopisywanych jest 20 mln rekordów? Biorąc pod uwagę ilość wiadomości na NK mowa tu już nawet nie o miliardach rekordów. Czy na prawdę duże portale korzystają z takiej właśnie techniki? Może jest inne, szybsze rozwiązanie?

    0
  • #6 14 Sty 2012 17:04
    walek33
    Poziom 28  

    Popieram wypowiedzi kol. marcinj12. To co próbujesz zrobić ma się nijak do prawidłowego działania DB. Proponuję więc skorzystać z jego pomocy.

    Cytat:
    nie wiem jak MySql blokuje rekordy

    zależnie od "silniczka" blokuje całą tabelę lub pojedynczy rekord.
    Cytat:
    Z bazy danych nic "magicznie" samo z siebie nie ma prawa znikać.

    Zgodnie z teorią "bool-a" prawda. Sam zresztą napisałeś w swoim poście, że wartości w bazie są, więc nie znikły.
    Cytat:
    W ten sposób tworzonych byłoby wiele niepotrzebnych rekordów, a czytelność tabeli spadłaby praktycznie do zera

    Jak napisał nasz kolega tabela ma być czytelna dla urządzenia, które ją obrabia. Dla Ciebie pozostają kwerendy, widoki, raporty. I jest to naprawdę wystarczająca ilość narzędzi dla czytelnego przedstawienia danych.

    0
  • #7 14 Sty 2012 18:08
    marcinj12
    Poziom 40  

    malum napisał:
    Dla przykładu nasza-klasa ma pewnie ze 20 mln użytkowników, każdy wysyła wiadomości, to jak mam rozumieć po każdym wysłaniu wiadomości do bazy danych dopisywanych jest 20 mln rekordów?
    Pytanie jak działa NK to pytanie raczej do jej autorów, choć wątpię by chcieli na nie odpowiedzieć...
    Ale na logikę rzecz biorąc: jeśli każdy z 20mln użytkowników portalu wyśle innemu użytkownikowi wiadomość o losowej treści, to żeby odbiorca mógł tą treść odczytać po jakimś czasie - TAK, treść każdej z tych 20mln wiadomości musi zostać zapisana gdzieś w bazie. Raczej nie tworzy się 20mln kolumn, więc pozostaje 20mln rekordów.
    malum napisał:
    Może jest inne, szybsze rozwiązanie?
    Szybsze od czego?
    Do dużych zastosowań używa się innych (płatnych) systemów bazodanowych, które są przeznaczone i optymalizowane do pracy z dużymi ilościami danych (Oracle, Sql Server). Wtedy w grę wchodzą różne metody optymalizacji ("tuningu") baz danych, są od tego specjaliści / administratorzy baz, którzy się głównie tym zajmują, ale o to się na razie martwić nie musisz... Przy dobrze założonych indeksach na tabeli i dobrze zaprojektowanych zapytaniach (na tym bym się głównie skupił), masz spokój do co najmniej do kilkudziesięciu milionów rekordów.

    0
  • #8 14 Sty 2012 22:27
    arcykowal
    Poziom 2  

    Oracle ma darmową wersję bazy danych.

    0
  • #9 17 Mar 2012 15:06
    malum
    Poziom 23  

    Dzięki za podpowiedzi, przeorganizowałem bazę danych i wszystko działa.

    Temat uważam za zamknięty.

    0