webForumDet fria alternativet

Designfråga: Rader istället för kolumner osv?

Databaser & SQL

13 svar · 1 024 visningar · startad av bananskalet

Medlem sedan feb. 200722 inlägg
Frågan#1

Hej, jag har en fråga angående databasdesign. Ifall det spelar roll så är det i Oracle (som jag är ny på, men jag har mångårig erfarenhet av SQL Server).
Våra system fylls ständigt på med ny data, och i det här fallet ska användarna kunna plocka fram rapporter som exv visar aktuella uppgifter. Dvs användaren väljer rapport, ställer in kriterier, klickar på Utför, och väntar en stund tills rapporten är färdigframställd.

Jag hittar på ett exempel (i verkligen finns förstås massor av tabeller osv).

Idag finns en tabell med nyckel och 6 st kolumner.

Tabell1 (ID1, k1, k2, k3, k4, k5, k6)

14 st nya fält, k101-k114, skall läggas till.

Detta kan förstås göras på flera olika sätt (se nedan)...

----
A-varianten:

Befintlig tabell utökas med de nya kolumnerna.

Tab1 (ID1, k1, k2, k3, k4, k5, k6, k101, k102, k103 ... k114)

(Inget joinande mellan tabeller behövs.)

---

B-varianten:

De nya kolumnerna läggs i separat tabell med samma nyckel.

Tab1 (ID1, k1, k2, k3, k4, k5, k6)
Tab101 (ID1, k101, k102, k103, k104, k105, ... , k114)

Tabellerna joinas enkelt via ID1.

----
C-varianten:

De nya kolumnerna läggs i separat tabell med koppling via syntetisk nyckel.

Tab1 (ID1, k1, k2, k3, k4, k5, k6, ID101)
Tab101 (ID101, k101, k102, k103, k104, k105, ... , k114)

Här har vi t ex en syntetisk nyckel i Tab101, samt en referens till den via ny kolumn i Tab1.
Tabellerna joinas enkelt via ID101.

----
D-varianten:

Ett par kollegor till mig valde dock en helt annan lösning.

Vi har alltså
Tab1 (ID1, k1, k2, k3, k4, k5, k6)

Därefter skapade de en tabell för de nya kolumnerna, vilka lagras som rader(!):
Tab100 (ID100, Klartext)

som t ex kan innehålla
1, 'k101'
2, 'k104'
3, 'k102'
4, 'k114'
...
14, 'k112'

Dessutom har man lagt till en kopplingstabell mellan de båda ovanstående tabellerna, där man lagt vart och ett av de 14 nya värdena som en egen rad:
TabK (ID1, ID100, Värde)

Som jag förstår det behövs därmed 29(?) st joinar, istället för 1 st, för att få tag i de 14 nya attributen.

select Tab1.ID, t101.Värde, t102.Värde, t103.Värde, t104.Värde ... t114.Värde
from Tab1 t1, TabK tk1, Tab100 t101
            , TabK tk2, Tab100 t102
            , TabK tk3, Tab100 t103
            , TabK tk4, Tab100 t104
            , TabK tk5, Tab100 t105
            , TabK tk6, Tab100 t106
            , TabK tk7, Tab100 t107
            , TabK tk8, Tab100 t108
            , TabK tk9, Tab100 t109
            , TabK tk10, Tab100 t110
            , TabK tk11, Tab100 t111
            , TabK tk12, Tab100 t112
            , TabK tk13, Tab100 t113
            , TabK tk14, Tab100 t114
where Tab1.ID1 = tk1.ID1  and Tab100.ID = tk1.ID100
 and  Tab1.ID1 = tk2.ID1  and Tab100.ID = tk2.ID100
 and  Tab1.ID1 = tk3.ID1  and Tab100.ID = tk3.ID100
 and  Tab1.ID1 = tk4.ID1  and Tab100.ID = tk4.ID100
 and  Tab1.ID1 = tk5.ID1  and Tab100.ID = tk5.ID100
 and  Tab1.ID1 = tk6.ID1  and Tab100.ID = tk6.ID100
 and  Tab1.ID1 = tk7.ID1  and Tab100.ID = tk7.ID100
 and  Tab1.ID1 = tk8.ID1  and Tab100.ID = tk8.ID100
 and  Tab1.ID1 = tk9.ID1  and Tab100.ID = tk9.ID100
 and  Tab1.ID1 = tk10.ID1  and Tab100.ID = tk10.ID100
 and  Tab1.ID1 = tk11.ID1  and Tab100.ID = tk11.ID100
 and  Tab1.ID1 = tk12.ID1  and Tab100.ID = tk12.ID100
 and  Tab1.ID1 = tk13.ID1  and Tab100.ID = tk13.ID100
 and  Tab1.ID1 = tk14.ID1  and Tab100.ID = tk14.ID100

Kanske har jag missförstått nåt, men eftersom man sparar infon radvis istället för kolumnvis så tänker jag mig
att det blir 14 st fler joinar. Plus ytterligare dubbelt så många pga kopplingstabellen mittemellan.
(I händelse av att exv 15 joinar räcker så är det lugnt för min del, jag är liksom främst ute efter själva principen.)

(Ska man koppla ihop andra saker från andra tabeller så växer förstås antalet joinar ännu mer.)

------------
Vad är bäst?
------------

En av kollegorna hävdar följande fördelar med D-varianten:
+ mer flexibel (eftersom man slipper göra alter table ifall nya attribut tillkommer)
+ minst lika bra prestanda som A/B/C-varianterna.
+ skapar bättre struktur/design

Stämmer ovanstående?
Finns andra fördelar?

Överväger fördelarna?

Rörande flexibiliteten i samband med att framtida nya attribut tillkommer, så tänker jag mig att det snarare är bättre med alter table. Dels går det snabbt, och dels ger det omedelbart en elegant och verklighetsnära design, samtidigt som inga joiner eller villkor behöver förändras.
Att som i D-varianten istället göra inserts är förstås smidigt i sig, men medför att man för att få tag i de nya attributen ifråga kommer behöva joina ännu mer och kanske ändra i villkors-satser i script.

Rörande prestandabiten tänker jag mig, utan att vara någon prestandaexpert, att man snarare förlorar än vinner rörande svarstider..? Typ att 29 st joinar som regel tar längre tid än 1..??

I övrigt ser jag själv mest nackelar:
* Krångligare, och tar längre tid, att designa och utveckla.
* Krångligare att hålla ordning på alla relationer, joinar/villkor osv i databasen.
* Svårare få överblick över vad man egentligen håller på med (dvs verksamhetsbiten)
* Svårare sätta sig in i för andra.
* Krångligare och svårare att skriva selects-satser, etc, för att titta på data.

Medlem sedan apr. 2006190 inlägg
#2

Beror på vad det är för någon data. Kommer ni alltid behöva använda er av alla 20 "kolumner"? Hur förhåller sig datan till varandra? Du måste nog berätta lite mer ingående om tabellerna och datan dom ska innehålla för att man ska kunna svara på den frågan, men i 99,999% av fallen så måste det vara rent vansinne att göra som din kolega har föreslagit. :moose

Medlem sedan feb. 200722 inlägg
#3

Tack för feedback! Fler är välkomna att kommentera. ;)

Mitt intryck är också att det ter sig "vansinnigt", men det vore ju inte så populärt om jag sade högt.

Vet inte vad mer av större värde som finns att berätta. Liksom inga konstigheter. Av de 14 nya kolumnerna så är samtliga av typen decimaltal. De ska liksom bara visas i en rapport, samt att 7 av talen ifråga är procenttal som även används i varsin multiplikation med tal i tabellen Tab1. Allt lär visas i rapporten, så både kolumnerna i Tab01 och samtliga de nya kolumnerna används alltså.

Vi kommer så vitt jag tror alltså alltid att använda oss av alla 14 talen. (Vilket jag antar alltid kommer innebära 14 eller 28 extra joinar för att få tag i vart och ett av dem.)

Men... Varför väljer man att spara värdena som rader, dvs typ:
ID1, ID100, Värde
där ID1 refererar till en rad i Tab1 och ID100 talar om vilken slags värde det rör sig om.
?

Dvs exempelvis (vad gäller tabellen med själva värdena):
rad1, 1, 0.54
rad1, 2, 0.64
rad1, 3, 0.73
...
rad1, 14, 0.48
rad2, 1, 0.55
rad2, 2, 0.64
...
rad2, 14, 0.42
...
radn...

Varför sparar man dem som rader, och inte som kolumner?
Dvs exv:
radnr, kol1, kol2 ... kol14
rad1, 0.64, 0.75 ... 0.66
rad2, 0.44, 0.63 ... 0.47
...

Vore som sagt tacksam för mer feedback kring det här tänkandet. Ger det alltså bättre prestanda? Blir lättare att underhålla? Kommentarer som sagt välkomna.

Medlem sedan feb. 200722 inlägg
#4

Ursäkta om jag tjatar lite, men jag är mån om feedback och det vore uppskattat om fler ger feedback. Blir prestandan i D-varianten alltså verkligen markant bättre? Osv?

Moderator får gärna flytta tråden till databasforumet ifall det kanske genererar fler svar.

Medlem sedan apr. 2006190 inlägg
#5

Jämför man A med D varienten, så kan man i ditt fall komma fram till:

  • A är bättre struktur. Varför dela på data som hör ihopp som i D?
  • A ger 100 gånger bättre prestanda

Hoppas chefen byter ut dina kollegors julbonus mot en databasgrundkurs. §e

Medlem sedan feb. 200722 inlägg
#6

Tack för ytterligare feedback. :) (Och fler får fortfarande gärna tycka till i frågan!)

Ska försöka argumentera så gott det går med mina kollegor. ;) Men haken är att de är rätt så tuffa och dominanta av sig och man tenderar avbrytas efter typ 5 sekunder ("Ja, men nu gör vi såhär", "Nä, vi ska inte göra så", etc), så ju bättre argument jag har och desto färre sekunder de tar att framföra - desto bättre. Plus att jag vill förstå vitsen med hur de tänkt, dvs utöver att det är "mer flexibelt", "minst lika bra svarstider", etc. Jag är på gång att ta över huvudansvaret för systemet ifråga, och är den som framöver kommer få leva med det och de eventuella utvecklings-, testnings- och prestandaproblem man kan tänkas få av att välja "fel" lösning.

Jag har hur som helst nu suttit hemma och på min egen dator byggt upp och testat de olika varianterna. Så jag kan ju passa på att redogöra lite, så kanske jag hjälper någon annan som läser här (alternativt får mothugg, vilket förstås också är välkommet).

Lade in 3000 poster i "huvudtabellen", i form av löpande idnr och 7/14/21 st fejkade slumptal (float) mellan 0 och 100.
(I skarpa miljön lär komma finnas hundratusentals poster.)
Satte sedan getdate() före och efter selectsatsen, som i samtliga fallen bestod i en select count(*). (Kanske inte optimal metod, men nu blev det så.)
Jag hade även provat olika sätt att indexera och tog det sätt som visade sig mest gynnsamt för D-varianten.
Har kört select-satserna ett antal gånger vardera, och svarstiderna jag återgivit är de som jag typ 9 gånger av 10 fått.

Att ha allt i samma tabell (id + 7 kolumner + 14 nya kolumner):
Sökning på allt: 0 till 0.017 sekunder.
Sökning på volym1 >= 90 (2972 träffar): 0 till 0.013 sekunder

Att ha i två tabeller med samma id i båda:
(id + 7 kolumner resp id + 14 kolumner)
Sökning på allt: 0 till 0.063 sekunder.
Sökning på volym1 >= 90 (2972 träffar): 0 till 0.017 sekunder

Att dela upp som i D-varianten:
Sökning på allt: ca 7.920 sekunder.
Sökning på volym1 >= 90 (2972 träffar): ca 3.360 sekunder

Jag vet att testet inte är optimalt gjort, men det gav mig ändå ett hum. Och det "hummet" är att D-varianten inte förefaller klart snabbare än de andra. Så utifrån prestandaskäl (svarstider) så torde inte D-varianten vara förstavalet.

Vill man uttrycka sig rakare på sak så gav den typ 100-1000 gånger längre svarstider.
(Samt att den krävde 29 st joinar istället för 0 eller 1, samt ca 42-44 and-satser istället för 0-2.)

PS: Bifogar selectsatsen för att testa D-varianten. Jag har förstås testat att den ger korrekt resultat, och and-satserna med kolbeskr är i enlighet med D-variantens design (utan dem har man såvitt jag förstått det hela inget hum om vilken kolumn man får tag i, eftersom man dessutom använder sig av syntetisk nyckel för Tab48).

select getdate()
select count(*)  --   (med index ca 7.92 sek)
from tab32urs t32
    ,tab48rad r1, tab47kop k1
    ,tab48rad r2, tab47kop k2
    ,tab48rad r3, tab47kop k3
    ,tab48rad r4, tab47kop k4
    ,tab48rad r5, tab47kop k5
    ,tab48rad r6, tab47kop k6
    ,tab48rad r7, tab47kop k7
    ,tab48rad r8, tab47kop k8
    ,tab48rad r9, tab47kop k9
    ,tab48rad r10, tab47kop k10
    ,tab48rad r11, tab47kop k11
    ,tab48rad r12, tab47kop k12
    ,tab48rad r13, tab47kop k13
    ,tab48rad r14, tab47kop k14
where 1=1
 and t32.volym1 >= 90  --(955 träffar)        (med index ca 3.36 sek)
 and k1.id32 = t32.id32 and r1.id48 = k1.id48    and r1.kolbeskr = 'vikt1'
 and k2.id32 = t32.id32 and r2.id48 = k2.id48    and r2.kolbeskr = 'vikt2'
 and k3.id32 = t32.id32 and r3.id48 = k3.id48    and r3.kolbeskr = 'vikt3'
 and k4.id32 = t32.id32 and r4.id48 = k4.id48    and r4.kolbeskr = 'vikt4'
 and k5.id32 = t32.id32 and r5.id48 = k5.id48    and r5.kolbeskr = 'vikt5'
 and k6.id32 = t32.id32 and r6.id48 = k6.id48    and r6.kolbeskr = 'vikt6'
 and k7.id32 = t32.id32 and r7.id48 = k7.id48    and r7.kolbeskr = 'vikt7'
 and k8.id32 = t32.id32 and r8.id48 = k8.id48    and r8.kolbeskr = 'halt1'
 and k9.id32 = t32.id32 and r9.id48 = k9.id48    and r9.kolbeskr = 'halt2'
 and k10.id32 = t32.id32 and r10.id48 = k10.id48    and r10.kolbeskr = 'halt3'
 and k11.id32 = t32.id32 and r11.id48 = k11.id48    and r11.kolbeskr = 'halt4'
 and k12.id32 = t32.id32 and r12.id48 = k12.id48    and r12.kolbeskr = 'halt5'
 and k13.id32 = t32.id32 and r13.id48 = k13.id48    and r13.kolbeskr = 'halt6'
 and k14.id32 = t32.id32 and r14.id48 = k14.id48    and r14.kolbeskr = 'halt7'
select getdate()
Medlem sedan apr. 2006190 inlägg
#7

Du har tillräckligt med kött på benen för att köra över dina kolegor utan våran hjälp, just do it! :bire

Går dom ändå inte med på det så be dom ge konkreta exempel på varför D-designen är bättre så kan vi hjälpa till att bryta ner dom.

Medlem sedan feb. 20013 023 inlägg
#8

Dina kollegor är kanske inte så fel ute, jag ska försöka skriva mer ikväll.

Medlem sedan feb. 200722 inlägg
#9

clarkbones skrev:

Dina kollegor är kanske inte så fel ute, jag ska försöka skriva mer ikväll.

Tack, det ser jag i så fall fram emot med intresse.

Jag kan se fall där det är bra att spara data på sättet enligt D-varianten, exempelvis om man har typade tabeller. Likaså om man exempelvis har behov av att inifrån en appplikation låta användaren kunna lägga till begrepp m m. Har själv jobbat i sådana lösningar, och även komponerat några.

Dock... i det här aktuella fallet tycker jag nackdelarna kraftigt överväger (se argument i tidigare inägg). Detta baserat på vad fälten ska användas till, att användarna ej själva skall/kommer lägga till kolumner, etc. Plus förstås argumenten för prestandaförluster, "krångligare" struktur, svårare för testare m fl att via select-satser få fram data ur tabellerna, osv.

Bra är förstås om jag får ökad insikt i om jag missat några goda argument för D-varianten. Ju bättre koll på olika alternativ och dess fördelar/nackdelar, desto bättre. Jag tror beslut i frågan kommer tas på måndag eftermiddag.

Medlem sedan feb. 20013 023 inlägg
#10

Jag ändrar mig, jag läste förslag D snabbt och slarvigt. Ärlligt talat känns D helt barockt. Nu vet vi ju inte mer om kontexten än det lilla du beskrivit, men av dina förslag är det bara A som är någorlunda vettigt.

D) är ju som din kollega säger i vissa avseenden flexibel, men databasdesignen ska också vara logisk och reflektera verksamheten. Det underlättar underhåll, förståelsen då andra utvecklare ska skriva SQL. De kraven kan man definitivt säga att D inte uppfyller.

Prestanda blir ju i D:s fall som du märkt dåliga och skriva SQL mot det blir ju ett härke.
Som du påpekat så skulle det möjligen kunna vara en lösning om det fanns behov av att användaren skulle kunna lägga till kolumner, men i största allmänhet är det helt enkelt helt fel design. Dina kollegor ska du inte idiotförklara, men jag tror deras kunskaper om databasdesign är extremt bristfälliga.

Låt dig inte bli överkörd för du har rätt.

Medlem sedan feb. 200722 inlägg
#11

Tack så jättemycket för svaret. :)

Jag postade tråden i måndags em och nu är det fredag kväll, och hittills har ingen opponerat sig vilket gör att jag fortfarande inte fått något argument för att D-varianten i detta fallet skulle vara att föredra. Snarare har ni två som svarat varit inne på samma linje som mig, samt att åtminstone den ene av er dessutom tydligen är certifierad.

Så tack igen till er båda. :)

Medlem sedan jan. 20022 440 inlägg
#12

Då kan du väl markera tråden som löst också :)

Medlem sedan feb. 200722 inlägg
#13

Japp, lär göra det inom kort. Har ju det där mötet på måndag, så efter det tänkte jag posta slutresultatet av vad vi beslutat, och färdigmarkera tråden. ;)

Medlem sedan feb. 200722 inlägg
#14

Nu har mötet ägt rum mellan mig och de två kollegorna. Jag lyckades få in den ena ("designbossen") på min linje, och beslut har tagits om att skippa D-varianten och istället lägga de nya värdena i Tab32 (A-varianten). Puuh... och pust... Efter mötet har jag personligen kompletterat Tab32 samt droppat Tab47 och Tab48.
Nu återstår att försöka få bra diskussioner även kring databasdesignen i övrigt, men det får nog vänta tills nästa år... Lär dock inom kort kanske posta nån tråd om det också.
Puuh... som sagt. Nu ska jag försöka markera tråden som löst. Tack igen till er som hjälpt till.

262 ms totalt · 4 externa anrop · v20260731065814-full.6fe65c25
117 ms — deklarationer (db)
0 ms — hämta statistik (cache)
141 ms — hämta tråd, inlägg och bilagor (db)
118 ms — ändringar (db)