Avatar billede bumle90 Nybegynder
29. juni 2004 - 13:25 Der er 54 kommentarer og
1 løsning

Normaliserings spørgsmål

Jeg har en database, der rent meta-data mæssigt er ret så lille og overskuelig, men rent data-mæssigt er meget stor.
Databasen består som den er nu af kun 1 tabel med 8 attributter og ikke andet. Databasen har kørt som testbase i en periode i en afdeling nu. Der ligger i øjeblikket over 1 million tupler i databasen, og når applikationen bliver rullet ud for alvor bliver dette mange-doblet.
Så jeg satte mig ned og tænkte, selvom det måske er en meget lille tabel kan det nok godt betale sig at normalisere den ud for at spare data. Men jeg er ikke helt sikker på om det kan betale sig.
Selve systemet er et filscannings system der gemmer filnavne på samtlige filer i hele virksomheden. (der er omkring 2000 ansatte) Så det bliver en pænt stor database rent datamæssigt som sagt.
Informationerne jeg gemmer i databasen for hver fil er følgende:
Ip|Computernavn|Dato|Sti|Filnavn|Extension|Size|type|

(Type indikerer om det er en klient eller en server vi har med at gøre. Gir bedre overblik for en bruger)
Som sagt ligger det nu i én tabel, med en del redundante data. Fx. computernavn og ip står skrevet masser af gange.
Så mit spørgsmål er om det ville kunne betale sig at dele tabellen op i flere vha normalisering. Jeg er kommet frem til følgende forslag selv:

Autonummerering|Ip|Computernavn|Type|

compId|Dato|Sti|Filnavn|Extension|Size|

Autonummerring er en primærnøgler
compId svarer til disse numre, og agerer dermed fremmednøglen i filtabellen.
Ville det kunne betale sig at lave det således, eller er der en smartere måde at gribe problematikken an på?
Mvh. Bumle90
Avatar billede rasmusbg Nybegynder
29. juni 2004 - 13:36 #1
Det kan jo også ske, at samme filnavn ligger på flere af maskinerne. Det kunne f.eks. være filerne i C:\Windows. Der kan så eventuelt være forskellige datoer. Men med en måske lidt uortodoks link-tabel, kunne dette også laves i databasen. Så ville det komme til at se sådan ud:

Autonummerering|Ip|Computernavn|Type| - computertabellen

compId|Dato|filId| - linktabellen

filId|Sti|Filnavn|Extension|Size| - filtabellen

compId i linktabellen er stadig fremmednøgle til computertabellen. filId i linktabellen er fremmednøgle til filtabellen, hvor filId er også er en autogenereret primærnøgle.
Dato er flyttet over i linktabellen, for at man stadig kan angive en dato til hver enkel fil på hver enkel computer.
Avatar billede dadane Novice
29. juni 2004 - 13:37 #2
JA! Helt bestemt. Og det er også lettere når en maskine får nyt IP nummer.
Avatar billede jpvj Nybegynder
29. juni 2004 - 13:38 #3
Det lyder meget fornuftigt.

Dog kan jeg ikke rigtigt lidt IP - kører i med fast IP adresser, eller ...?
Avatar billede dadane Novice
29. juni 2004 - 13:40 #4
Rasmus' forslag er godt  - hvis du kan styre ens filer. På den vis slipper du også billere i backup (der bør måske være en checksum - bare så du ikke får taget backup af den éne virus fil der er og så distribuere den til alle de andre.)
Avatar billede bumle90 Nybegynder
29. juni 2004 - 13:41 #5
Nej, vi kører med dynamiske IP-adresser...så det blir lidt svært på den måde
Avatar billede bumle90 Nybegynder
29. juni 2004 - 13:42 #6
Jeg kan ikke lave en computertabel som er "statisk" da det vil forekomme at samme computer kan have forskellig ip...
Men stadig er det jo relativt sjældent at en IP skifter
Avatar billede bumle90 Nybegynder
29. juni 2004 - 13:43 #7
dadane, det er ikke selve filerne jeg har liggerne. Det er blot filnavn + sti osv. så jeg kan være ligeglad med virainficerede filer
Avatar billede bumle90 Nybegynder
29. juni 2004 - 13:44 #8
Den her filId, skulle det være en autonummerering?
Eller hvordan skal jeg identificere dem?
Avatar billede rasmusbg Nybegynder
29. juni 2004 - 13:46 #9
Jeps, det var tænkt som autonummerering
Avatar billede bumle90 Nybegynder
29. juni 2004 - 13:55 #10
Hmm det blir jo så bare lidt svært eftersom filerne bliver slettet og skrevet ned i databasen igen ved hvert scan.
Dvs. filerne får et nyt autonummer hver gang?
Holder det?
Avatar billede rasmusbg Nybegynder
29. juni 2004 - 14:05 #11
Det mest smarte ved scanninger ville være kun at skrive ændringerne i databasen i stedet for at starte forfra hver gang. Men jeg kan godt se, at der er et problem der, hvis en fil er blevet slettet på en af maskinerne mellem to scanninger.
Der må jeg sige, at jeg ikke lige har noget forslag...
Avatar billede bumle90 Nybegynder
29. juni 2004 - 14:18 #12
Mit problem bliver jo også at vedligeholde den tabel der identificerer de enkelte computere da vi ikke har faste IPer...Så skal jeg lave noget med hvis ip/compnavn kombination findes skal der kun opdateres i filtabellen, ellers skal der opdateres i begge tabeller og compId i filtabellen skal nu knyttes til det nye autonummer der bliver tildelt når den nye ip/compnavn bliver lagt i i computertabellen.
Bliver det ikke noget værre roderi mon?
Spørgsmålet er om det overhovedet kan betale sig...Jeg kan simpelthen ikke gennemskue det
Avatar billede bumle90 Nybegynder
29. juni 2004 - 14:20 #13
Der kommer jo alligevel til at være en trilliard tupler i den database, og feltet "sti" er defineret som en lang tekst. Altså en blob. Alene det felt kommer jo til at tage ufatteligt meget performance...Så måske så¨meget at det er ligemedet at ip/compnavn som er to almindelige tekstfelter og type som er en int, bliver gentaget en masse gange.
Hvad siger I?
Avatar billede rasmusbg Nybegynder
29. juni 2004 - 14:22 #14
Tjah...evt. kunne ip vel udelades? Forudsat, at alle maskiner har et computernavn.
Avatar billede bumle90 Nybegynder
29. juni 2004 - 14:24 #15
jamen det har de, men alligevel synes jeg bare det er sådan liiiidt du ved at lave ID på blot et computernavn. Så kunne man måske lave det på MAC adressen...men folk skifter jo konstant computere og dermed netkort....og så er man jo ligevidt
Avatar billede dadane Novice
29. juni 2004 - 14:32 #16
Hvorfor er stien en blob? Så vidt jeg husker (ret mig hvis jeg tager fejl) tillader hverken windows, dos, linux eller macos mere end allerhøjest 255 tegn (tror det ofte er det halve). Så en varchar skulle vel være alt rigeligt.

Og jeg tror stadig der er en del at spare ved at normalisere. Både i plads og i performance.

Performancemæssigt er spørgsmålet dog også - hvad gør du mest? Indsætter eller søger?
Avatar billede dadane Novice
29. juni 2004 - 14:33 #17
Endeligt kan man selvfølgelig blive helt praktisk og sige "if it works don't fix it".
Lad lortet køre inditl det bliver en nødvendighed at ændre noget.

Så bliver du også hurtigere færdig ;)
Avatar billede bumle90 Nybegynder
29. juni 2004 - 14:43 #18
Du er en klog mand dadane :)
Principperne er da i orden :P
Der vil køre langt flest indsættelser eftersom der kun bliver administratortne dvs. 5-10 mennesker der kommer til at søge i den, og over 2000 computere hvis filer vil blive indsat.
Hmmm ja..ser ud til du har ret i det med sti-længden. Jeg troede at det kun var mappenavnene der max måtte være 255 karakterer, og der måtte være vilkårligt mange mapper...Men kunne man ikke forestille sig at det snart bliver ændret?
Avatar billede dadane Novice
29. juni 2004 - 14:48 #19
Tjoeh, det er altid svært at forudsige hvilke ændringer andre laver, - men mon dog?

Bare af nysgerrighed, - hvad skal det bruges til?

Licenstjek? (Hvor mange har installeret program X version Y)
Seriøsitetstjek (et enkelt billede er o.k. - men 537 billeder som alle starter med XXX er ikke)?
Avatar billede bumle90 Nybegynder
29. juni 2004 - 14:49 #20
Ja, det må nok være det nederste.
Det skal give administratorerne et overblik over hvilke filer der flourerer rundt i virksomheden...Om filerne ligger korrekt og om folk ikke sidder med et hav af piratkopier og ting og sager på deres computer...
Avatar billede bumle90 Nybegynder
29. juni 2004 - 14:50 #21
Hele systemet har jeg faktisk lavet..og testen har kørt i et stykke tid i en afdeling på 30 ansatte....Der er så også nogle servere med osv. Men der ligger nu knap 1 million tupler i tabellen
Avatar billede bumle90 Nybegynder
29. juni 2004 - 14:52 #22
så det er ret store mængder data at arbejde med...og også derfor jeg begyndte at spekulere lidt.
Ikke fordi jeg havde da også tænkt de tanker inden jeg gik igang...men ville gerne have et produkt hurtigt på bordet
Nu tænkte jeg bare at jeg for min egen skyld måske burde lave databasen stabil også, så jeg ikke får allemulige irriterende vedligeholdelsesproblemer sidenhen
Avatar billede rasmusbg Nybegynder
29. juni 2004 - 14:54 #23
Hmmm...lidt off topic, men det er vedligeholdelse, man tjener penge på...hehe ;o)
Avatar billede arne_v Ekspert
29. juni 2004 - 16:10 #24
Jeg tror at jeg ville lave det som:

computer
--------
navn,PK
type
sidsteIP
sidstescan

fil
---
id,PK,autogenerate
computer,FK->computer
filsti
filnavn
filext
Avatar billede arne_v Ekspert
29. juni 2004 - 16:13 #25
Begrundelse:
* jeg tror ikke at du kan detecte hvis en computer skifter navn og så er computerid
  overflødigt
* sidsteIP giver også mening med DHCP
* sidstescan på computer tillader at scanne computere på forskelligt tidspunkt
  men uden at gemme en tid per fil
* de 4 felter i fil kunne faktisk godt være en sammensat PK men det synes jeg
  er for bøvlet derfor en autogenrated id
Avatar billede arne_v Ekspert
29. juni 2004 - 16:14 #26
Hov - der skal vist lige tilføjes et size felt til fil tabellen.
Avatar billede bumle90 Nybegynder
29. juni 2004 - 16:49 #27
Jeg tænkte på om det evt. ville være smart at lave en form for checksum på sti+filnavn+extension. Så kunne man på en eller anden måde udnytte det for ikke at skrive de samme stier 1000 gange.
Ville det være smart?
Avatar billede arne_v Ekspert
29. juni 2004 - 16:51 #28
Det kunne det sagtens være.

Så ville filsti erstattes af stiid.

Du ville spare en del plads. Og få en JOIN mere i mange queries.
Avatar billede bumle90 Nybegynder
30. juni 2004 - 00:04 #29
hmmm ja...hvordan ville man skulle lave det?
Findes der algoritmer til at lave checksumme?
Og hvad skulle jeg så sætte ind i databasen? Og hvad skulle jeg evt. lave checksum over?
Avatar billede arne_v Ekspert
30. juni 2004 - 00:11 #30
Jeg ville så bare lave:

computer
--------
navn,PK
type
sidsteIP
sidstescan

sti
---
id,PK
filsti

fil
---
id,PK,autogenerate
computer,FK->computer
stiid,FK->sti
filnavn
filext
size
Avatar billede bumle90 Nybegynder
30. juni 2004 - 09:21 #31
Ville du så lægge fx. checksummen for stien som "filsti" inde i sti tabellen?
Kunne man ikke med fordel også lave noget checksum på filnavn/ext/size tilsammen? og lægge de informationer ud i en tabel for sig, med en autogenereret ID som PK og i filtabellen skulle der så være en filID som FK der forbandt til den nye filtabel. Så man fik noget ala:

computer
--------
navn,PK
type
sidsteIP
sidstescan

sti
---
id,PK
checksum på(filsti)

fil
---
id,PK
Checksum på(filnavn,filext,size)

samling
---
id,PK,autogenerate
computer,FK->computer
stiid,FK->sti
filid,FK->filnavn,type og størrelse
Avatar billede arne_v Ekspert
30. juni 2004 - 11:04 #32
Efter lidt eftertanke så tror jeg ike påd en checksum ide. En FK til sti må
være det rigtige.
Avatar billede bumle90 Nybegynder
30. juni 2004 - 11:34 #33
Hvad mener du?
Avatar billede bumle90 Nybegynder
30. juni 2004 - 11:34 #34
At det er unødvendigt at lave checksumme?
Avatar billede arne_v Ekspert
30. juni 2004 - 11:49 #35
Ja
Avatar billede bumle90 Nybegynder
30. juni 2004 - 12:08 #36
hvorfor mener du det?
Avatar billede bumle90 Nybegynder
30. juni 2004 - 12:53 #37
Du mener data basen selv finder ud af at overholde den referentille integritet hvis jeg bare sletter/indsætter og opdaterer kaskadevis eller hvad?
Avatar billede arne_v Ekspert
30. juni 2004 - 13:33 #38
En FK stiid er betydeligt mere effektivt end den checksum

-------------------------

Nogen databaser understøtter cascade delete. Andre ikke.
Avatar billede bumle90 Nybegynder
30. juni 2004 - 14:07 #39
okay, det har du jo nok ret i.
Mht. at indsætte nye logs eller hvad man nu skal kalde dem i samlingstabellen. Så er jeg vel nødt til først at hive alle stier ud af sti tabellen, og derefter checke hvilken en jeg skal referere til vha. sammenligning af stier.
eller kan man på en eller anden måde lave en join i en insert eller noget andet smart ?
Avatar billede arne_v Ekspert
30. juni 2004 - 14:36 #40
Jeg ville lade stier være PC specifikke d.v.s. at når man processer en PC så sletter
man alle stier til den PC og opretter dem alle igen.
Avatar billede bumle90 Nybegynder
30. juni 2004 - 14:47 #41
Men der skal jo kun være en sti der hedder fx. C:\winnt
På den måde kan alle der har en sådan sti referere til den...og der kan derved spares kolossale mængder data...Det er da skide smart
Avatar billede bumle90 Nybegynder
30. juni 2004 - 14:47 #42
Hvis stierne var pc-specifikke ville man jo ikke spare specielt meget
Avatar billede bumle90 Nybegynder
30. juni 2004 - 14:58 #43
Kan du se hvad jeg gør galt her?
Jeg vil bare hive en int ud af databasen

                string sql3;
                printf("debug1");
                sqlstr="SELECT ID FROM Files";
                printf("debug2");
                stat = SQLExecDirect(stmt,(SQLCHAR *)sqlstr,strlen(sqlstr));
                  if((stat!=SQL_SUCCESS)&&(stat!=SQL_SUCCESS_WITH_INFO))
                  {
                      printf("Error in ExecDirect %i og %i\n",stat,SQL_ERROR);
                  }
                printf("%i",linectr);
Avatar billede bumle90 Nybegynder
30. juni 2004 - 14:59 #44
sqlstr er en char*
Avatar billede bumle90 Nybegynder
30. juni 2004 - 15:01 #45
Jeg connecter på samme måde som du viste mig engang
http://www.eksperten.dk/spm/455186
Avatar billede arne_v Ekspert
30. juni 2004 - 15:23 #46
Ja.

Når du scanner skal du kun indsætte 1 række i sti og X rækker i fil.
Avatar billede bumle90 Nybegynder
30. juni 2004 - 15:52 #47
jeg prøver lige at sende en lidt mere komplet kode


#include <stdio.h>
#include <stdlib.h>

#include <windows.h>
#include <sql.h>
#include <sqlext.h>

char* constr =  "Driver={Microsoft Access Driver (*.mdb)};Dbq=\\\\ntbrb02\\databaser\\filscantest.mdb;Uid=Admin;Pwd=;";
char* sqlstr = "SELECT ComputerNavn FROM Computers";

int main(int argc, char *argv[])
{
  SQLHENV Environment;
  SQLHDBC DataBaseConnect;
  SQLHSTMT stmt;
  SQLRETURN stat;
  int i,il,sl,outconlen;
  char s[100],outconstr[1024];
  stat = SQLAllocEnv(&Environment);
  if((stat!=SQL_SUCCESS)&&(stat!=SQL_SUCCESS_WITH_INFO)) printf("Error in AllocEnv\n");
  stat = SQLAllocConnect(Environment,&DataBaseConnect);
  if((stat!=SQL_SUCCESS)&&(stat!=SQL_SUCCESS_WITH_INFO)) printf("Error in AllocConnect\n");
  stat = SQLDriverConnect(DataBaseConnect,NULL,
                    (SQLCHAR *)constr,(SQLSMALLINT)strlen(constr),
                    (SQLCHAR *)outconstr, (SQLSMALLINT)sizeof(outconstr),
                    (SQLSMALLINT *)&outconlen,SQL_DRIVER_COMPLETE);
  if((stat!=SQL_SUCCESS)&&(stat!=SQL_SUCCESS_WITH_INFO)) printf("Error in Connect\n");
  stat = SQLAllocStmt(DataBaseConnect,&stmt);
  if((stat!=SQL_SUCCESS)&&(stat!=SQL_SUCCESS_WITH_INFO)) printf("Error in AllocStmt\n");
  stat = SQLExecDirect(stmt,(SQLCHAR *)sqlstr,strlen(sqlstr));
  if((stat!=SQL_SUCCESS)&&(stat!=SQL_SUCCESS_WITH_INFO)) printf("Error in ExecDirect\n");
  /*
  stat = SQLBindCol(stmt,1,SQL_C_LONG,&i,sizeof(i),(SQLINTEGER *)&il);
  if((stat!=SQL_SUCCESS)&&(stat!=SQL_SUCCESS_WITH_INFO)) printf("Error in BindCol\n");
  */
  stat = SQLBindCol(stmt,2,SQL_C_CHAR,s,sizeof(s),(SQLINTEGER *)&sl);
  if((stat!=SQL_SUCCESS)&&(stat!=SQL_SUCCESS_WITH_INFO)) printf("Error in BindCol\n");
  for(;;) {
    stat = SQLFetch(stmt);
    if((stat!=SQL_SUCCESS)&&(stat!=SQL_SUCCESS_WITH_INFO)) break;
    s[2] = '\0';
    printf("%s\n",s);
  }
  SQLFreeStmt(stmt,SQL_DROP);
  SQLDisconnect(DataBaseConnect);
  SQLFreeConnect(DataBaseConnect);
  SQLFreeEnv(Environment); 
  return 0;
}
Avatar billede bumle90 Nybegynder
30. juni 2004 - 15:54 #48
s[2] = '\0';
Har jeg også prøvet med
s[sl] = '\0';
Det dur ikke.
sl = -89125478
Avatar billede arne_v Ekspert
30. juni 2004 - 16:04 #49
Prøv:

stat = SQLBindCol(stmt,1,SQL_C_CHAR,s,sizeof(s),(SQLINTEGER *)&sl);

og

s[sl] = '\0';
Avatar billede arne_v Ekspert
30. juni 2004 - 16:04 #50
andet argument er kolonne nummeret i resultatet hvis jeg husker rigtigt
Avatar billede bumle90 Nybegynder
30. juni 2004 - 16:20 #51
JEg fandt vidst ud af det tror jeg.
Jeg havde glemt at kalde stat = SQLAllocStmt(DataBaseConnect,&stmt); for hver forespørgsel
Avatar billede bumle90 Nybegynder
30. juni 2004 - 17:00 #52
Okay, nu ser det ud til at køre...
Endnu et tvivlspg. (Håber ikke jeg presser citronen for meget :) )
Mht. felterne filnavn,ext,size
Lige nu ligger de som du forslog i den samlede tabel.
Men her vil der givet vis også kunne spares en del da ufattelig mange filnavne vil være de samme. Samme filnavn,størrelse og extension.
Ville det være smart at lægge hver ud i sin egen tabel, på samme måde som med stien og så have en reference i samlingstabellen, eller hvad?
Sagen er jo nemlig den at man skal kunne søge på alle attributterne, så hvis man havde dem i hver sin tabel, måske med undtagelse af filstørrelse ville dette godt kunne lade sig gøre. Hvad siger du til denne ide?
Det er jo sådan set bare en viderebygning til det du skrev
Avatar billede arne_v Ekspert
30. juni 2004 - 18:33 #53
Jeg tror at pladsbesparelsen i forhold til omkostningen ved både insert og select
gøt at det ikke kan betale sig.
Avatar billede bumle90 Nybegynder
01. juli 2004 - 13:35 #54
Og forresten vil jeg gerne lige gi dig point her arne hvis du dropper et svar :)
Avatar billede arne_v Ekspert
01. juli 2004 - 13:39 #55
svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester