Uso corretto delle tabelle di ricerca


25

Ho problemi a capire esattamente come posizionare i limiti per quando e dove utilizzare le tabelle di ricerca in un database. La maggior parte delle fonti che ho visto dicono che non potrò mai averne troppi ma, a un certo punto, sembra che il database sarebbe suddiviso in così tanti pezzi che, sebbene possa essere efficiente, non è più gestibile. Ecco un esempio di ciò su cui sto lavorando:

Diciamo che ho un tavolo chiamato Employees:

ID  LName   FName   Gender  Position
1   Doe     John    Male    Manager
2   Doe     Jane    Female  Sales
3   Smith   John    Male    Sales

Fingi per un momento che i dati siano più complessi e contengano centinaia di righe. La cosa più ovvia che vedo che potrebbe essere spostata in una tabella di ricerca sarebbe Posizione. Potrei creare una tabella denominata Posizioni e incollare le chiavi esterne dalla tabella Posizioni nella tabella Impiegati nella colonna Posizione.

ID  Position
1   Manager
2   Sales

Ma fino a che punto posso continuare a suddividere le informazioni in tabelle di ricerca più piccole prima che diventino ingestibili? Potrei creare una tabella Sesso e avere 1 corrisponde a Maschio e 2 corrispondono a Femmina in una tabella di ricerca separata. Potrei persino mettere LNames e FNames nelle tabelle. Tutte le voci "John" vengono sostituite con una chiave esterna di 1 che punta alla tabella FName che indica che un ID di 1 corrisponde a John. Se vai in questa tana del coniglio troppo in questo modo, però, la tabella dei tuoi dipendenti viene ridotta a un casino di chiavi esterne:

ID  LName   FName   Gender  Position
1   1       1       1       1
2   1       2       2       2
3   2       1       1       2

Sebbene ciò possa o meno essere più efficiente da elaborare per un server, questo è certamente illeggibile per una persona normale che potrebbe tentare di mantenerlo e rende più difficile per uno sviluppatore dell'applicazione tentare di accedervi. Quindi, la mia vera domanda è quanto è troppo lontano? Esistono "buone pratiche" per questo genere di cose o una buona serie di linee guida da qualche parte? Non riesco a trovare alcuna informazione online che risolva davvero un buon insieme di linee guida utilizzabili per questo particolare problema che sto riscontrando. La progettazione del database è per me un vecchio cappello, ma la BUONA progettazione del database è molto nuova, quindi le risposte eccessivamente tecniche potrebbero essere sopra la mia testa. Qualsiasi aiuto sarebbe apprezzato!


5
L'uso delle tabelle "lookup" è una cosa. Sostituire il testo con numeri ID è una cosa completamente diversa.
Mike Sherrill "Cat Recall",

1
Il genere potrebbe non essere sempre fissato a 2 valori! Ora che abbiamo delle transizioni di genere, chi vuol dire che un'applicazione potrebbe non aver bisogno di ulteriori categorie come 'nato maschio ora femmina' o 'nato femmina ora maschio'.

@ Mike, bel commento!
Walter Mitty,

Nel mio negozio i pensatori sono stati in grado di fermarsi dopo che solo quattro scelte, maschio, femmina, transessuale, non avrebbero rivelato.
kevinsky,

Risposte:


22

Ma fino a che punto posso continuare a suddividere le informazioni in tabelle di ricerca più piccole prima che diventino ingestibili? Potrei creare una tabella Gender e avere 1 corrisponde a Male e 2 corrispondono a Female in una tabella di ricerca separata.

Stai mescolando due diversi problemi. Un problema è l'uso di una tabella "lookup"; l'altro è l'uso di chiavi surrogate (numeri identificativi).

Inizia con questa tabella.

ID  LName   FName   Gender  Position
1   Doe     John    Male    Manager
2   Doe     Jane    Female  Sales
3   Smith   John    Male    Sales

È possibile creare una tabella di "ricerca" per posizioni come questa.

create table positions (
  pos_name varchar(10) primary key
);

insert into positions
select distinct position 
from employees;

alter table employees
add constraint emp_fk1
foreign key (position) 
  references positions (pos_name);

La tabella originale appare esattamente come prima della creazione della tabella "lookup". E la tabella dei dipendenti non richiede join aggiuntivi per ottenere dati utili e leggibili dall'uomo.

L'uso di una tabella "lookup" si riduce a questo: l'applicazione richiede il controllo sui valori di input forniti da un riferimento di chiave esterna? In tal caso, puoi sempre utilizzare una tabella di "ricerca". (Indipendentemente dal fatto che utilizzi una chiave surrogata.)

In alcuni casi, sarai in grado di popolare completamente quella tabella in fase di progettazione. In altri casi, gli utenti devono essere in grado di aggiungere righe a quella tabella in fase di esecuzione. (E probabilmente dovrai includere alcuni processi amministrativi per rivedere nuovi dati.) Il genere, che in realtà ha uno standard ISO , può essere completamente popolato in fase di progettazione. I nomi delle strade per gli ordini internazionali di prodotti online probabilmente devono essere aggiunti in fase di esecuzione.


2
Non sapevo che potessi fare tutto questo! Il modo in cui funziona il tuo metodo è piuttosto bello. Grazie!
Brad Turner,

4
Ho aderito a DBA Stack Exchange solo per poter votare questa risposta. Questo è bellissimo e non mi è mai venuto in mente. Grazie!
CindyH,

Apprezzo il metodo per popolare la tabella di ricerca. La mia ragione per leggere questa domanda era vedere se ci sarebbe stato un vantaggio che non potevo vedere con una chiave surrogata nelle mie tabelle di ricerca. Mi hai confermato che un singolo campo di testo è buono e utile come sembra. Grazie.
Sinthia V,

8

Nella tabella Dipendenti, avrei solo una ricerca di "Posizione" perché è un insieme limitato di dati che può espandersi.

  • Il genere è auto-descrittivo (dire Mo F), limitato a 2 valori e può essere applicato con un vincolo CHECK. Non aggiungerai nuovi sessi (ignorando i bollock di correttezza politica)
  • Il nome "John" non fa parte di un insieme limitato e limitato di dati: il potenziale insieme di dati è enorme al punto da essere effettivamente illimitato, quindi non dovrebbe essere una ricerca

Se si desidera aggiungere una nuova posizione, è sufficiente aggiungere una riga alla tabella di ricerca. Ciò rimuove anche le anomalie nella modifica dei dati, che è un punto di normalizzazione

Inoltre, una volta che hai un milione di dipendenti, è più efficiente archiviare PositionID tinyint di varchar.

Aggiungiamo una nuova colonna "valuta salariale". Userei una tabella di ricerca qui con una chiave di CHF, GBP, EUR, USD ecc: non userei una chiave surrogata. Ciò potrebbe essere limitato con un vincolo CHECK come Gender, ma è un insieme limitato ma espandibile di dati come Position. Faccio questo esempio perché userei la chiave naturale anche se appare in un milione di righe di dati dei dipendenti nonostante sia char (3) piuttosto che tinyint

Quindi, per riassumere, usi le tabelle di ricerca

  1. dove hai una serie di dati finiti, ma espandibili in una colonna
  2. dove non è auto-descrivente
  3. per evitare anomalie nella modifica dei dati

1
Una possibile ragione per inserire il genere in una tabella di ricerca è la localizzazione.
a_horse_with_no_name

1
"Genere ... (diciamo M o F), limitato a 2 valori ... ignorando i bollock di correttezza politica" - Ironia della sorte, è la stessa correttezza politica che sembri detestare che induce le persone a erroneamente "genere" (' Maschile "," Femminile ") quando significano" sesso "(" Maschio "," Femmina "). Se il contesto è di genere grammaticale, di solito ci sono più di due valori. Se il contesto registra il sesso di un neonato, allora ci sono almeno quattro valori ("non è stato valutato ufficialmente" e "la valutazione ufficiale è stata inconcludente"). ps non intendo sembrare duro, mi è piaciuta l'ironia :)
quando

4
@onedaywhen: il valore corretto per una colonna chiamata "Sesso" è "Sì, per favore". A meno che tu non sia britannico
gbn il

Il termine "anomalie" viene qui utilizzato in modo improprio poiché il termine ha un significato particolare diverso legato alla normalizzazione e il collegamento non è appropriato.
philipxy,

5

La risposta è "dipende". Non molto soddisfacente, ma ci sono molte influenze che spingono e tirano il design. Se hai programmatori di app che progettano il database, una struttura come quella descritta funziona per loro perché l'ORM nasconde la complessità. Ti strapperai i capelli quando scrivi i rapporti e dovrai unirti a dieci tavoli per ottenere un indirizzo.

Progettare per l'uso, l'uso previsto e l'uso futuro probabile. È qui che entra in gioco la tua conoscenza del processo aziendale. Se stai progettando un database per un'azienda veterinaria, ci sono ipotesi ragionevoli su dimensioni, utilizzo e indicazioni in termini di funzionalità che saranno piuttosto diverse rispetto a una start-up ad alta tecnologia.

Per riutilizzare una citazione preferita

"Una volta un saggio mi ha detto" normalizza fino a quando fa male, denormalizza fino a quando funziona ".

Da qualche parte lì c'è il punto debole. La mia esperienza è stata che avere un ID chiave in più di un tavolo non è un crimine così grave come alcuni pensano se non si cambiano mai le chiavi primarie.

Prendi questo esempio abbreviato di tabelle altamente normalizzate da un sistema reale

CREATE TABLE PROPERTY
(ID                          NUMBER(9)           NOT NULL);

CREATE TABLE PROPERTY_TYPE
(ID                          NUMBER(9)           NOT NULL);

CREATE TABLE PROPERTY_LOCALE 
PROPERTY_ID                  NUMBER(9)           NOT NULL,
(LOCALE_ID                   NUMBER(9)           NOT NULL,  --language 
VALUE                        VARCHAR2(200)       NOT NULL);

CREATE TABLE PROPERTY_DEPENDENCY
(PROPERTY_ID                 NUMBER(9)           NOT NULL,
 PARENT_PROPERTY_ID          NUMBER(9)                   ,
 PROPERTY_TYPE_ID            NUMBER(9)           NOT NULL);

Queste tabelle impostano un elenco collegato di singole proprietà e proprietà figlio padre e vengono utilizzate qui

  CREATE TABLE CASE_PROPERTY
  (ID                        NUMBER(9)           NOT NULL,
  PARENT_ID                  NUMBER(9),
  CASE_ID                    NUMBER(9)           NOT NULL,
  PROPERTY_ID                NUMBER(9),
  PROPERTY_TYPE_ID           NUMBER(9)           NOT NULL);

Sembra perfetto: ottieni tutti i casi con un property_id in una selezione

Otteniamo un elenco da cui scegliere

 Select pl.value, pd.property_id
 from property_locale pl, property_dependency pd
 where pl.property_id = pd.property_id
 and pd.property_type_id = 2;  --example number

Ora prova a selezionare tutte le proprietà di un caso se ha property_types di 3 e 4 e 5, oppure no ...

SELECT   cp2.case_id,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 2
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE1,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 34
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE2,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 4
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE3
  FROM   case_property cp2
 WHERE   cp2.case_id = 10293  

Questo fa male ... anche quando usi modi più eleganti per affrontarlo. Tuttavia, aggiungi un po 'di de normalizzazione suddividendo le proprietà per le quali un caso avrà solo un property_id e questo potrebbe essere molto meglio.

Per sapere quando hai troppe tabelle o non abbastanza prova a interrogare il database con domande che verranno utilizzate dall'applicazione, da un rapporto e da un'analisi annuale.


5
I numeri ID non hanno nulla a che fare con la normalizzazione. Solo perché ogni tabella ha un numero ID non significa che sia in 5NF o anche in 3NF. Significa solo che devi fare molti join per estrarre i dati utilizzabili da quella tabella.
Mike Sherrill 'Cat Recall',
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.