DB parti di progettazione

8

Sto sviluppando uno strumento che gestisce parti (elettriche). Le parti possono essere create, visualizzate, modificate, cancellate, raggruppate e così via ...

Per rendere questa domanda utile per i futuri visitatori mi piace mantenere questa domanda universale poiché la gestione delle parti in un DB è molto comune, indipendentemente da quali parti siano presenti nel DB (CD, automobili, cibo, studenti, ...) .

Sto pensando a 3 diversi progetti di DB:

  1. Utilizzo di una tabella delle parti e tabelle derivate per attributi di parti specializzati.

    Parts      (id, part_type_id, name)
    PartTypes  (id, name)
    Wires      (id, part_id, lenght, diameter, material)
    Contacts   (id, part_id, description, picture)
    
  2. Utilizzando solo tabelle di parti specializzate.

    Wires      (id, name, lenght, diameter, material)
    Contacts   (id, name, description, picture)
    
  3. Utilizzo di una tabella Parts-, PartTypes-, ValueTypes- e PartValues che contengono tutti i valori.

    PartTypes  (id, name)
    ValueTypes (id, part_type_id, name)
    Parts      (id, part_type_id, name)
    PartValues (part_id, value_type_id, value)
    

Quale preferire e perché? O c'è uno migliore?
Sono preoccupato per le query DB. Non voglio che le query diventino eccessivamente lente o complicate.

Aggiornamento

Il numero di tipi nel DB è praticamente dato e statico poiché si basa su uno standard internazionale e verrà potenziato di rado.

    
posta juergen d 27.12.2012 - 17:10
fonte

7 risposte

16

Opzione 3 : (a volte)
L'opzione 3 è il "EAV" design. In teoria è bello perché i campi vengono estratti dalla struttura della tabella e diventano dati. Ma dà prestazioni terribili. Inoltre, non consente l'uso dell'indicizzazione corretta. E rende le query molto più complicate.

Userei l'EAV solo in circostanze speciali. Ho usato EAV per calcolare le parti ausiliarie necessarie per gli ordini e ha funzionato bene. Ma sii molto stanco di usarlo come design per i tuoi tavoli principali.

Opzione 2 : (mai?)
L'opzione 2 è un no no. E i campi condivisi? Hai intenzione di duplicare la struttura della tabella per ogni campo condiviso? Richiederebbe di includere i sindacati nei report dell'intero sistema.

Opzione 1 : (vincitore!)
L'opzione 1 potrebbe sembrare un po 'troppo semplice, ma probabilmente è la migliore scommessa per i tuoi tavoli principali. Tutte le parti utilizzano la stessa tabella principale per i campi condivisi in modo da evitare i sindacati nei report. Ha grandi prestazioni che consentono il corretto utilizzo dell'indicizzazione. Le query sono nello stile tradizionale e sono semplici.

Lo svantaggio dell'opzione 1 è che non puoi aggiungere campi dinamicamente. Ma lo vuoi davvero? Aggiungendo dinamicamente i campi si sta eseguendo la progettazione del database in fase di esecuzione.

    
risposta data 27.12.2012 - 20:01
fonte
6

Tenderei a non scegliere l'opzione # 3.

L'opzione n. 3 è l'impostazione della coppia nome-valore che viola la normalizzazione.

Idealmente, si tenta di avere un certo livello di normalizzazione del database. Impegnarsi per la completa normalizzazione e quindi denormalizzare se necessario quando viene identificato per problemi di personalizzazione o di prestazioni.

Considera la query "quali sono il nome e gli ID delle parti per tutti i fili di rame"

La struttura # 1 è

select
  name, parts.id
from
  wire, parts
where
  wire.material = 'copper'
  and wire.part_id = parts.id

La struttura # 2 è

select id, name from wire where material = 'copper'

La struttura # 3 è

select
  parts.name,
  parts.id,
from
  parts, part_types, part_values, value_types
where
  part_types.name = "wire"
  and parts.part_type_id = part_types.id
  and value_types.name = "material"
  and value_types.id = part_values.type_value_id
  and part_values.value = "copper"

Considera anche la complicazione degli inserimenti e delle eliminazioni dal sistema.

Qualche ulteriore lettura sul perché no # 3 - La maledizione della coppia valore nome

    
risposta data 27.12.2012 - 18:24
fonte
4

Vado opzione 3

L'opzione 1 è errata perché non vuoi che i tuoi join siano basati su un valore archiviato. (cioè If type ="Wire" join to TblWire )

L'opzione 2 è errata perché non hai modo di generare rapporti sull'inventario nel suo complesso

    
risposta data 27.12.2012 - 17:43
fonte
4

Vorrei iniziare con un modello di dati / oggetto che consente l'ereditarietà e quindi utilizzare una mappatura relazionale di oggetti . In questo modo ottieni una classe base Parts e sottoclassi come Wires , Contacts ecc. Ora, se si applica una strategia "mappa-ogni-classe-a-propria-tabella", si ottiene l'opzione 1, che è la soluzione più "normalizzata" e dovrebbe essere la strategia canonica se non hai più informazioni sulle query che ti aspetti.

L'opzione 2 è ciò che ottieni applicando un approccio "map-each-concrete-class-to-own-table". Questo può evitare "join" e può funzionare meglio per qualche tipo in caso di query (in particolare query per un solo "tipo di parte"), d'altra parte rende più complessa e più lenta la gestione generica con tutte le parti. Evita questo se non hai motivi particolari per questo.

L'opzione 3 è ciò di cui hai bisogno solo se desideri che l'utente modifichi il numero di tipi di parti in fase di esecuzione - se non ti aspetti tale requisito, l'opzione 3 sarà un esempio perfetto per le cose di over-engineering.

    
risposta data 30.12.2012 - 21:38
fonte
2

Con il database DB NOSQL (come MongoDB per esempio) avrai solo bisogno di un set chiamato "Parts". Ogni parte di quel set è il cosiddetto documento - registra con un set di campi variabile:

{
   "_id": ObjectId("4efa8d2b7d284dea1"),
   "partType": "wire",
   "length": 102.5,
   "diameter": 1.5,
   "material": "silver"
}, 
{
   "_id": ObjectId("4efa8d2b7d284sjsq23d"),
   "partType": "contact",
   "description": "something",
   "picture": Binary(...)
}, 

Penso che questa sia l'archiviazione di dati più naturale per l'attività che descrivi.

    
risposta data 30.12.2012 - 20:35
fonte
2

Assolutamente andare con l'opzione 1 ma con alcune semplici modifiche:

Parts      (id, part_type_id, name)
PartTypes  (id, name)
Wires      (id, part_id, part_type_id, lenght, diameter, material)
Contacts   (id, part_id, part_type_id, description, picture)

È quindi possibile utilizzare i vincoli CHECK e i valori DEFAULT per garantire che il part_type_id sia corretto e quindi è possibile partecipare sia a part_type_id che a part_id. Ciò evita di avere un join condizionale basato su una sola tabella, e se è necessario aggiungere un part_type_id ai fili (diciamo che stiamo suddividendo quella parte e aggiungendo un'altra tabella di attributi estesi) i vincoli di default e di controllo possono essere modificati.

    
risposta data 19.02.2013 - 03:18
fonte
1

L'opzione 3 è più generica e può ospitare più casi d'uso.

Se vai all'opzione 3 potresti aver bisogno di più join e query complesse per funzionalità semplici, nell'opzione 2 avresti bisogno di query complesse per funzionalità "grandi" come inventario e rapporti e potrebbe essere necessario utilizzare i sindacati per farlo.

Puoi sempre semplificare le tue query nelle opzioni 3 usando Views, se molto spesso hai bisogno solo del filo o del contatto, crea una vista per ognuna di esse. Puoi ottimizzarlo se diventa necessario.

    
risposta data 27.12.2012 - 18:08
fonte

Leggi altre domande sui tag