Lista winnt@man.lodz.pl
[Lista archiwów] [Inne Listy]

Re: [WINNT] Serwer dla MS-SQL (crosspost)

To: winnt@man.lodz.pl
Subject: Re: [WINNT] Serwer dla MS-SQL (crosspost)
From: Adam <a.g@poczta.onet.pl>
Date: Sat, 19 Apr 2014 22:11:50 +0200
W dniu 2014-04-19 21:03, wloochacz pisze:
W dniu 2014-04-19 19:00, Adam pisze:
(...)
Ale to jeszcze o niczym nie świadczy.
Widziałem (nie pamiętam, gdzie) pola typu DECIMAL(15,2) używane do
przechowywania flagi, gdzie wystarczyłoby pole SMALLINT.
Wystarczyłoby - a i pewnie, ale tak się nie projektuje dużego systemu.
Najpierw definiujesz sobie własne typy danych (domneny), a potem ich
używasz. jakbym miał w kazdym polu każdej tabeli okreslać typ i rozmiar
to by mnie k...wica strzeliła bardzo szybko :)

Nie rozumiem.
Wydawało mi się, że definiując tabelę w SQL, należy też zdefiniować
poszczególne pola, czyli przykładowo:
Oczywiście, że pola trzeba zdefiniować - pisałem o typach danych
(domenach, czyli wg terminologii MSSQL "User-Definied Data Types");
Spójrz - w tym przykładzie definicja tabeli jest oparta na standardowych
typach danych i OK.
Ale...

CREATE TABLE [CDN].[TraNag](
     [TrN_TrNID] [int] IDENTITY(1,1) NOT NULL,
     [TrN_RelTrNId] [int] NULL,
     [TrN_FVMarza] [tinyint] NULL,
     [TrN_DDfId] [int] NULL,
     [TrN_TypDokumentu] [int] NOT NULL,
     [TrN_ZwrId] [int] NULL,
     [TrN_ZwrIdWZKK] [int] NULL,
     [TrN_FaId] [int] NULL,
     [TrN_NumerNr] [int] NOT NULL,
     [TrN_NumerString] [varchar](31) NOT NULL,

itd.
Moja tabela wygląda np. tak:
CREATE TABLE [dbo].[tDfLogEntity]
(
[IdEntity] [dbo].[uNAME_L] NOT NULL,
[PkValue] [dbo].[uNAME_M] NOT NULL,
[IdUser] [dbo].[uINT] NOT NULL,
[LogType] [char] [uName_S] NOT NULL,
[LogDate] [dbo].[uDATE_TIME] NOT NULL,
[UpdateCount] [dbo].[uINT_BIG] NOT NULL
)
Np. definicja domnety uNAME_L wygląda tak:
CREATE TYPE [dbo].[uNAME_L] FROM [varchar](80) NULL

I potem posługujesz się wszedzie własnymi typami, nie muszisz się
zastanawiać czy to był varchar(80) czy 180...
To po prostu wygodne i łatwe do utrzymania.

Z Twojego punktu widzenia - może to być czytelne.
Ale z punktu widzenia producenta programu - chyba niekoniecznie.
Jeśli ktoś wypuszcza program "do ludzi", to wydaje mi się, że lepiej jest, aby typy były typowe ;)

_Management_Studio_ pokazuje (dla TraNag):

CREATE TABLE [CDN].[TraNag](
        [TrN_TrNID] [int] IDENTITY(1,1) NOT NULL,
        [TrN_TerminZwrotuKaucji] [datetime] NULL,
        [TrN_OFFPrawoDoFAPA] [tinyint] NULL,
        [TrN_OFFPrawoDoAnulowania] [tinyint] NULL,
        [TrN_RelTrNId] [int] NULL,
        [TrN_FVMarza] [tinyint] NULL,
        [TrN_DDfId] [int] NULL,
        [TrN_TypDokumentu] [int] NOT NULL,
        [TrN_ZwrId] [int] NULL,
        [TrN_FaId] [int] NULL,
        [TrN_NumerNr] [int] NOT NULL,
        [TrN_NumerString] [varchar](31) NOT NULL,
        [TrN_Bufor] [smallint] NOT NULL,
        [TrN_Anulowany] [int] NOT NULL,
        [TrN_VaNId] [int] NULL,
        [TrN_DataDok] [datetime] NOT NULL,
        [TrN_DataWys] [datetime] NOT NULL,
        [TrN_DataOpe] [datetime] NOT NULL,
        [TrN_NumerObcy] [varchar](30) NOT NULL,
(...)

_Dokumentacja_ pokazuje:

Nazwa // Typ // Opis // Opcje
TrN_TrNID // INTEGER // Identyfikator rekordu // Unikalny identyfikator rekordu. Poprzez to pole realizowane są wszystkie relacje typu 1:MANY do innych tabel. // IDENTITY(1,1)

TrN_RelTrNId // INTEGER// Pomocnicze pole relacji miedzy dokumentami

TrN_FVMarza // TINYINT // Faktura marza 1 - Faktura marza

TrN_FVMarzaRodzaj // TINYINT // Faktura marza rodzaj 1- Procedura marży dla biur podróży 2- Procedura marży – towary używane 3- Procedura marży – dzieła sztuki 4- Procedura marży – przedmioty kolekcjonerskie i antyki

TrN_DDfId // INTEGER // Identyfikator dokumentu w tabeli DokDefinicje

TrN_TypDokumentu // INTEGER // Typ dokumentu (klasa dokumentu z tabeli DokDefinicje) // NOT NULL

TrN_ZwrId // INTEGER // Identyfikator dokumentu źrodlowego dla dokumentów korygujących

TrN_ZwrIdWZKK // INTEGER // Identyfikator dokumentu źrodlowego dla dokumentów korygujących WZKK

TrN_FaId // INTEGER // Wskaźnik do faktury wykorzystywany przy przekształacaniu paragonów i WZ do faktury W paragonie lub WZ jest tu TrNId faktury, do której został przekształcony dokument źródłowy

TrN_NumerNr // INTEGER // Autonumerowany czlon numeru dokumentu // NOT NULL

TrN_NumerString // VARCHAR(31) Stały (parametryzowalny) człon numeru dokumentu // NOT NULL

TrN_NumerPelny // COMPUTED|VARCHAR(30) Pełny numer dokumentu Numer wyliczany funkcją serwerową // CDN.FN_NUMERPELNY(TRN_NUMERNR,TRN_NUMERSTRING)

TrN_Bufor // SMALLINT // Stan dokumentu  1 - bufor,
0 - zatwierdzony, -1 - anulowany // NOT NULL
(...)

itd., później opisy kluczy i relacji.
Oczywiście wszystko tabelarycznie, tutaj próbowałem to "przełożyć" na "płaski" txt.

Wydaje mi się (przy aktualnym stanie mojej wiedzy), że gdyby ktoś dostał dokumentację z nadanymi własnymi, nietypowymi nazwami typów danych, to musiałby dostać jeszcze "słownik" owych typów - dodatkowa niepotrzebna translacja ;)


Poza tym mam własne rpzmyślenia na nazywanie table, procedur, pól itd w
bazie danych. To co jest w CDN mi się nie podoba; uważam za zbyteczne
dodowanie przedrostka do nazwy pola, który określa z jakiej jest tabeli.
Po co to? Przecież od tego są aliasy, czyli:
select H.TrN_ZwrTyp,
        H.TrN_ZwrFirma,
        H.TrN_ZwrNumer,
        L.TrE_JmFormatZ,
        L.TrE_TypJm,
        L.TrE_PrzeliczM,
        L.TrE_PrzeliczL,
        L.TrE_GrupaPod
from CDN.TraNag H
inner join CDN.TraElem L on (L.TrE_GIDNumer = H.TrN_GIDNumer)


Aliasy są wykorzystywane.

U mnie każde pole nazywa się dokładnie tak samo w każdej tabeli, jeśli
niesie tę samą informację logiczną (np. kod klienta, nr dokumentu,
itd.). Ale to wynika też z pewnych mechanizmów w programowaniu
apliakcji, ale to już zupełnie inna bajka...

Tutaj chyba też:

Tabele TraNag (1:MANY) TraElem
Pola łączące TrN_TrNID = TrE_TrNId
Opcje Klucz obcy FK_TrETraNag


(...)
Używanie triggerów do zapewnienia integralności referencyjnej jest, moim
zdaniem, błędem. Jest tylko jeden przypadek, kiedy trzeba użyć takiego
mechanizmu w MSSQL - ale to wyjątek od reguły.

Optima jest (była?) pomyślana jako system "strojony" pod klienta.
Naprawą baz w założeniu mieli się zajmować serwisanci o różnym stopniu
wiedzy.
W dobrze zaprojektowanej i wdrożonej aplikacji (i bazie danych
oczywiście) nie ma prawa zdarzyć się coś takiego jak "popsuta baza".
Nie wiem, może za mało widziałem, ale... Zajmuję się MSSQLem od wersji
2000 na poważnie i nigdy nie miałem przypadku popsutej bazy danych, na
poziomie serwera.
Braki w danych, osercone dokumenty, zagubione transkacje - pewnie, że
było. Ale to był efekt źle zaprojektowanej apliakcji. Tylko i wyłącznie.

Nie wiem, czy dobrze się wyraziłem.

Przykład:
Klient się "walnął" i z jakichś powodów trzeba fakturę wycować "do bufora" ("Bufor" oznacza, że dokument jest zapisany, ale nie zatwierdzony "na stałe", można go dowolnie zmieniać lub usunąć).

Przy wycofaniu do bufora trzeba pamiętać, aby wycofać dokumenty magazynowe (czyli WZ), wycofać płatności (czyli KP), wrócić ewentualne rezerwacje i jeszcze wiele innych rzeczy. Wydaje mi się, że gdyby nie było triggerów, to serwisant mógłby przykładowo wycofać WZ, przywrócić rezerwacje, ale zapomniałby o wycofaniu płatności.

Tym zajmują się triggery.

Czy dobrze myślę?


Stąd też np. przy kasowaniu rekordu (bezpośrednio w bazie danych) w
TraNag (nagłówku transakcji) sprawdzane są najprzeróżniejsze warunki,
takie jak rezerwacje, płatności, stany na poszczególnych magazynach i
całe mnóstwo innych. Stąd ktoś (nawet przypadkowy), kto "dobierze się"
do bazy danych SQL nawet prostym skanerem, nie jest w stanie jej zepsuć.
No, chyba że zna polecenie:
Alter table cdn.JakasTabela disable trigger all
Po pierwsze - nikt normalny nie daje bezpośredniego dostępu do bazy
danych. To jak gmeranie w nosie odbezpieczonym granatem.
Robiłem takie cuda, jasne - alke to wymaga perfekcyjnej znajomości
logiki aplikacji i mechanizmów bazy danych. Jak nie popsujesz coś w
danych, to mozesz spowodować eskalację blokad - na przykład.

Czasami zdarza się go używać, ostatnio np. musiałem zmienić definicję
numeracji kasy na "żywym" raporcie kasowym z SYMBOL/NR/ROK na
SYMBOL/NR/KASA/ROK czy jakoś tak.

Tak więc z mojego punktu widzenia trigger jest co najmniej pomocny, żeby
nie powiedzieć niezbędny. Ale być może czegoś nie wiem.
:-)
Nie obraź się, ale właśnie zacytowałeś mi standardową regułkę
producenta, który musi jakoś przekonać innych do swojego rozwiązania.
Ale ja tego nie kupuję ;-)
Więcej - mam wyrobione zdanie na ten temat poparte doświadczeniem gdzie
było mniej więcej podobnie. I nigdy więcej!
Tj. spora część logiki była zaszyta w bazie danych, ale to nie było
dobre. Moje doświadczenia to nie tylko wdrażanie, ale też rozwój i
utrzymanie tak napisanej aplikacji.

Ale jeśli utrzymaniem aplikacji zajmuje się cały tabun studentów?

Jeśli dodatkowe funkcje (i triggery, i coś tam jeszcze) dopisuje "tysiąc" dystrybutorów i dealerów?



Dlaczego uważam to za niezbyt szczęśliwe rozwiązanie? Po pierwsze i
najważniejsze - rozproszona odpowiedzialność (nie wiem czy programujesz,
ale zapoznaj się z zasadą SOLID a ja tu piszę o pierwszej z nich, czyli
"single responsibility").

No właśnie.
Niedouczony serwisant nie da rady "zbuforować" przykładowej faktury, nie robiąc całego ciągu zdarzeń z tym związanego. Albo spełni wszystkie warunki, aby móc zbuforować fakturę, albo trigger poinformuje go, że zapomniał wycofać płatność.


Nie do końca wiadomo co robi aplikacja (i dlaczego), a co robi baza (i
dlaczego). Ja chcę mieć spokój i uważam, że aplikacja powinna być
wygodna w rozwouju i elastyczna w dostosowaniu.
Od tej pory minimalizuję logikę w bazie do minimum - de-facto poza
utrzymaniem integralności więcej logiki tam nie ma.
Tak, tak - wiem - to taki święty Graal aplikacji biznesowych ;-)

Nie wyobrażam sobie "gmerania" na bazie danych z
kilkudziesięciostronicowym materiałem opisującym jakieś zależności czy
uwarunkowania.
Tyle to pikuś :D
Co powiesz na to; ok. 1100 tabel i 12 tyś procedur? Oczywiście zero
dokumentacji technicznej - tylko aplikacja i profiler.
I weź w tym gmeraj ;-)


Można się załamać :(

Ja tak uczyłem się wieki temu pisać w Clarionie 2.1 for DOS - widziałem aplikację, miałem szczątek dokumentacji po angielsku (a wtedy znałem może kilkadziesiąt słow po angielsku) i widziałem, co aplikacja robi.
Próbowałem to powtórzyć.
Dopiero jakieś 3 lata później ktoś napisał podręcznik w jęz. polskim. Napisał zresztą 2 tomy, ale jak z nim rozmawiałem, to drugiego nie udało się wydać.
Internetu jeszcze nie było, tylko Fido i BBS-y.




Ale pogadamy może nieco później - Wesołych Świąt :)


--
Pozdrawiam.

Adam

<Pop. w Wątku] Aktualny Wątek [Nast. w Wątku>