È un modo ridicolo di strutturare uno schema DB o mi manca completamente qualcosa?


61

Ho svolto un bel po 'di lavoro con i database relazionali e penso di aver capito abbastanza bene i concetti di base della buona progettazione di schemi. Di recente mi è stato affidato il compito di rilevare un progetto in cui il DB era stato progettato da un consulente ben pagato. Per favore fatemi sapere se il mio intestino - "WTF ??!?" - è garantito, o è un tale genio che sta operando fuori dal mio regno?

DB in questione è un'app interna utilizzata per inserire richieste dai dipendenti. Solo guardando una piccola sezione di esso, hai informazioni sugli utenti e informazioni sulla richiesta che viene effettuata. Lo progetterei così:

Tabella utente:

UserID (primary Key, indexed, no dupes)
FirstName
LastName
Department

Tabella richiesta

RequestID (primary Key, indexed, no dupes)
<...> various data fields containing request details
UserID -- foreign key associated with User table

Semplice vero?

Il consulente lo ha progettato in questo modo (con dati di esempio):

UsersTable

UserID  FirstName   LastName
234     John        Doe
516     Jane        Doe
123     Foo         Bar

DepartmentsTable

DepartmentID   Name
1              Sales
2              HR
3              IT

UserDepartmentTable

UserDepartmentID   UserID   Department
1                  234      2
2                  516      2
3                  123      1

RequestTable

RequestID   UserID   <...>
1           516      blah
2           516      blah
3           234      blah

L'intero database è costruito in questo modo, con ogni pezzo di dati incapsulato nella propria tabella, con ID numerici che collegano tutto insieme. Apparentemente il consulente aveva letto di OLAP e voleva la "velocità delle ricerche intere"

Ha anche un gran numero di procedure memorizzate per incrociare tutte queste tabelle.

Questo design è valido per un database SQL di piccole e medie dimensioni?

Grazie per commenti / risposte ...


12
Oh ragazzo, se questo ti fa dire WTF, allora probabilmente non hai visto tabelle con oltre 200 colonne e stored procedure lunghe più di 1000 righe.
Giobbe

42
+1 per non aver cancellato dopo esserti sentito in imbarazzo. Grazie per aver lasciato questo così gli altri possono imparare.
Wayne Koorts,

2
@Job - in realtà, non lo sono - non sono un DBA per il commercio (ormai abbastanza ovvio! Lol), quindi la mia soglia SQL WTF è abbastanza bassa. Anche se mi manca completamente il punto del design del consulente, ho fatto sì che WTF avesse le mie capacità. Hai mai avuto una giornata in cui ti senti stupido ?
Jim,

9
@Jim: Congratulazioni, hai trasformato una giornata stupida in una giornata illuminata .
Wayne Koorts,

3
Maledici quei consulenti ben pagati!
davidsleeps,

Risposte:


73

Ha perfettamente senso per me. È solo molto normalizzato, il che conferisce molta flessibilità che altrimenti non avresti. I dati non normalizzati sono un dolore al sedere.


la tua risposta ha perfettamente senso, e guardando la mia domanda e lo schema forse è solo il semplice numero di tavoli che sta usando che mi ha confuso. Ho semplificato notevolmente l'esempio per la mia domanda, ma vedo come il concetto sia valido: sta semplicemente dividendo le cose molto più di quanto vorrei. Sospiro, immagino sia una buona cosa non essere un DBA! :)
Jim,

Impara a progettare secondo la regola dei dieci minuti: "Ciò che è vero ora probabilmente non lo sarà tra dieci minuti." Assicurati che i tuoi progetti possano gestire i cambiamenti.
Blrfl,

1
Questo schema ha in realtà il vantaggio che quando un dipendente viene inserito, il suo reparto deve esistere.
Simon Richter,

@SimonRichter: non è vero. Il Dipendente può essere creato senza alcun Reparto esistente, e anche il contrario.
Daniel Dinnyes,

@SimonRichter Il vantaggio di questo progetto è, in primo luogo, che il Dipartimento è un'entità separata e, in secondo luogo, che esiste una relazione molti-a-molti tra Dipartimento e Dipendente, al contrario dell'esempio dei PO, dove era "molti- to-one-ish "(non potevo dire molti-a-uno, poiché nessuna entità dipartimentale separata faceva riferimento per essere chiamata relazione).
Daniel Dinnyes,

48

Non penso che un WTF sia garantito o che il ragazzo stia facendo un progetto geniale pazzo: è una normalizzazione del database piuttosto standard.

Il motivo della tabella dei reparti è che se non si inseriscono i reparti in una tabella separata, è necessario trattare con gli utenti nei reparti "Vendite", "Vendite", "Venditori", "Vele" e "Vendita", a meno che tu non faccia qualcosa per impedirlo. E avere il tavolo extra è (parte di) il modo migliore che conosco per farlo.

Se ci dovrebbe essere una tabella UserDepartment è una chiamata più dura, il che ovviamente significa che nessuna delle due decisioni è fuori strada e folle. Da un lato è un dolore quando tutto il design e la logica del tuo tavolo hanno assunto un reparto per utente e poi le modifiche, dall'altro fare un ulteriore join senza motivo per anni e anni è una possibilità reale e anche un dolore.

Personalmente concordo con te sul fatto che la tabella UserDepartment è probabilmente eccessiva. Anche se è incluso, è probabile che nel tempo le persone scriveranno query che presumono che vi sia un solo utente per reparto, quindi finirai con il peggio di entrambi i mondi: un ulteriore join senza motivo prima di aver bisogno del tavolo, e il codice non funziona comunque quando viene consentito più di un reparto per utente.

MODIFICA - Un fattore chiave per stabilire se le relazioni da molti a molti devono essere supportate è se le regole aziendali sono chiare. Se non hai idea di come funzionerebbe un utente in più reparti, non ha molto senso aggiungere la tabella, poiché il tuo codice non può probabilmente gestire correttamente i casi in cui un utente si trova in più reparti.

Immagina di aver autorizzato molti dipartimenti per utente, per ogni evenienza. È stata quindi implementata una regola aziendale per l'assegnazione delle commissioni, in base al dipartimento. Quindi sono stati ammessi più dipartimenti. Fortunatamente, hai anche avuto la lungimiranza di scrivere il tuo codice di commissione in modo da tenerne conto. Sfortunatamente, hai aggiunto le commissioni di ciascun dipartimento per gli utenti di entrambi. La direzione voleva che tu ti basassi sul ruolo delle persone per ogni vendita. Quindi, quanto era buono avere il tavolo in anticipo? Che dire degli altri tavoli che hai avuto "per ogni evenienza" che non sono mai stati necessari?

MODIFICA DOPO - Un altro motivo per cui il consulente potrebbe aver voluto aggiungere tutte quelle tabelle intermedie è stato affrontato in questa domanda di follow-up , le risposte alle quali forniscono alcuni motivi per cui il refactoring di un database è solitamente più difficile del codice di refactoring, che tende a spingerti verso l'approccio "inserisci tutti i tavoli di cui potresti mai aver bisogno".


Penso che tu abbia espresso a parole quello che era il mio WTF - il ragazzo sta usando TONNATE di questi tavoli internazionali, e mi è sembrato così stupido. Ora che l'ho suddiviso in un esempio molto più piccolo per questa domanda, mi sento piuttosto stupido per pubblicarlo dal momento che non sembra poi così male.
Jim,

5
Come puoi vedere da molti dei commenti, c'è un sano scetticismo su "ci saranno sempre e solo una X per Y". Il consulente si sta coprendo dai reclami "come mai ci possono essere solo una X per Y". Alcuni dei quali probabilmente verranno fuori. Ma non sarà responsabile del mantenimento del codice che ha molti join (non troppo male, ma più difficile) e che deve essere corretto rispetto alle regole di business che non esistono ancora (male) - immagina la domanda "perché gli utenti ottengono TUTTO i permessi di ogni dipartimento, dovrebbero ottenere il PIÙ BASSO di ogni permesso "o qualcosa del genere.
psr

@psr Penso che ci sia un errore di battitura: le "query che presumono che vi sia un solo utente per reparto" non dovrebbero essere "query" che presuppongono che un utente si trovi in ​​un solo dipartimento "?
BiAiB,

@BiAiB - hai ragione, questo è ciò che intendevo dire.
psr

14

Se il requisito è avere più reparti per utente, questo design ha senso. L'unico inconveniente d'essa rappresenta l' UserDepartmentTableavere una chiave surrogata UserDepartmentIDche non è necessario (basta fare la UserIde DepartmentIduna chiave primaria composta).

Se un utente appartiene sempre e solo a un singolo reparto, il tuo design ha senso (anche se una tabella di ricerca di reparto sarebbe comunque una buona cosa).


18
... Fino a quando non è possibile più di un dipartimento per utente.
Blrfl,

1
Esatto, @Blrfl. Quello che oggi non accadrà mai è il CEO di domani che sta avendo un aneurisma perché non lo fa.
Adam Crossland,

2
Parte della decisione di cosa sia degno di quel tipo di trattamento è capire il dominio del problema. In alcune applicazioni, potrebbe essere importante sapere che il dipendente # 3804 è stato conosciuto dalla società come Ann Smith e Ann Jones (dopo essersi sposati), il che renderebbe normale normalizzare il nome dal tavolo dei dipendenti. Nel caso di Jim, potrebbe valere la pena espandere la tabella degli interruttori per mantenere una cronologia in modo che se Ann passa dall'HR all'IT, il fatto che una vecchia richiesta legata a lei possa riflettere che si trattava davvero di una richiesta delle risorse umane e non dell'IT.
Blrfl,

8
YAGNI: i database possono essere refactored.
JeffO,

2
@Oded, Alcuni mappatori ORM come Entity Framework non funzionano bene con le tabelle che hanno una chiave primaria composita.
maple_shaft

5

Alcuni requisiti non sono chiari nella tua domanda. La risposta corretta dipende da cosa vuole il tuo cliente - Se fossi in te, chiederei al cliente di questo:

0-Qual è la differenza tra un utente e un dipendente?

1-Supponendo che un dipendente = utente, cosa succede se un dipendente cambia reparto?

2-Un gruppo di dipendenti può fare 1 richiesta?

3-Potrebbe un dipendente appartenere a più di un dipartimento? Che dire del CEO

4-Esiste un sottoinsieme di dipendenti a cui è consentito effettuare richieste?

5-Cosa succede alla richiesta quando un record di un dipendente viene eliminato (se mai)?

6-Potresti cancellare una richiesta? Cosa succede quando la richiesta viene cancellata (assicurarsi di non eliminare il record dei dipendenti da RI)

7-Può il dipendente fare la "stessa" richiesta più di una volta (definire la "stessa")

8-Come gestire le richieste per i dipendenti che lasciano l'azienda (annullare le loro richieste o eliminare le richieste?)

Potrebbero esserci più domande, ma il mio punto è che la soluzione dipende da requisiti esatti e portata del progetto. Una volta determinato, lo schema può essere derivato direttamente. Di conseguenza, entrambe le soluzioni presentate potrebbero essere corrette.


+1 queste sono grandi domande che devono essere chiarite prima di progettare questo tipo di schema. Mi piace il tuo flusso di logica.

@ Surfer513: apprezzo il tuo bel commento.
NoChance,

1

Vorrei aggiungere un paio di note in forma di punto che parlano esplicitamente di alcuni dei potenziali vantaggi dell'utilizzo di una tabella di join nel modo in cui ha fatto il vostro consulente ben pagato.

  • Indicizzato correttamente (ad esempio, se UserDepartmentTable indicizza le due chiavi esterne), si verifica solo una piccola perdita di prestazioni di una tabella di join come questa a causa delle chiavi esterne non univoche. Se le chiavi esterne sono garantite come uniche, secondo la piccola teoria del database che conosco, cercare UserDepartmentTable.Departmentnon è più "difficile" che cercare qualsiasi altra colonna nella Usertabella.
  • La tabella di join offre maggiore flessibilità nell'impostazione di altre informazioni sull'associazione tra l'utente e il reparto (ad es. Timestamp sulla creazione).
  • La tabella di join consente di "versione" dell'associazione abbastanza facilmente (ad esempio, quando un utente cambia reparto, attiva un flag booleano indice come UserDepartmentTable.Activefalso e crea una nuova associazione attiva). È anche possibile avere il versioning dell'associazione di reparto con il modello a due tabelle (solo Utente e Reparto), ma è più difficile e richiede l'aggiunta di almeno un'altra colonna o l'esecuzione di acrobazie del database al fine di evitare la duplicazione delle chiavi primarie.
  • Ti consente di assegnare abbastanza facilmente associazioni uno-a-molti o molti-a-uno o molti-a-molti.

Detto questo, ci sono diversi motivi per NON fare ciò che ha fatto il tuo consulente ben pagato.

  • Tutti i vantaggi di cui sopra sono tutti anticipatori di possibili esigenze future, complicando troppo le cose per i giorni nostri. Non è conforme a YAGNI. È di banale difficoltà in seguito scrivere una migrazione che si sposta dal modello a due tabelle a un modello di tabella join. Puoi farlo quando emerge l'esigenza aziendale. Farlo prima può essere fonte di confusione.
  • Confonde altri sviluppatori. Mentre, sì, direi che l'aspettativa di uno sviluppatore web della tua statura (in cui stai esaminando le decisioni dei consulenti) sarebbe quella di comprendere e riconoscere una tabella di join, è ancora più complicata del necessario e considerando la mancanza di esigenze aziendali, provoca confusione.

bella analisi - tuttavia, non direi che ho una statura come sviluppatore nel mio lavoro diurno, tranne per il fatto che sono l'unico qui a sapere qualcosa su db / c # / vb / etc ... quindi suppongo di essere parte time dev di default. questo è un progetto abbastanza piccolo, quindi i consulenti hanno visto un gran numero di tavoli e join che mi hanno lasciato dire "wtf" (ma grazie a te brava gente ora sto dicendo "oic ...")
Jim

Un argomento piuttosto vecchio, ma comunque rilevante ... il refactoring può essere molto difficile, immagina di avere bisogno di più reparti in futuro invece di uno, ma hai solo un ID reparto in Utenti come FK. Probabilmente finirai con referendes duplicati (Users.DeptID e UsersDepartmentsTable) o spazzatura completa, come elenchi separati da virgole in Users.DeptID o XML. La soluzione corretta non potrebbe essere facilmente aggiunta, come suggerito da YAGNI o KISS, ma sarebbe ostruita.
Erik Hart,

0

Senza la struttura completa delle informazioni necessarie non posso dire che sia terribile o no. Ma almeno il pezzo mostrato non è di "WTF". Sembra solo una terza forma normale di struttura dei dati (beh, teoricamente abbiamo anche una quarta e una quinta)

Alcuni colloqui possono avere spazio per UserDepartmentTable tra due scuole di chiavi "naturali" e "artificiali" nel pezzo mostrato. Niente di più, come posso vedere

La normalizzazione è la regola del buon sviluppatore / progettista di DB per molte ragioni, * de * le normalizzazioni vengono utilizzate a volte nel mezzo degli sviluppi per lo speed-win, principalmente

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.