it-swarm.it

Uso corretto delle tabelle di ricerca

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 posso 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 chiamata 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 Gender e avere 1 corrisponde a Male e 2 corrispondono a Female 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 gestirlo e rendere più difficile per uno sviluppatore di applicazioni 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!

25
Brad Turner

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 richiede nessun 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 un 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.

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

  • Il genere è auto-descrittivo (diciamo M o 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. Questo rimuove anche 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, si usano 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
8
gbn

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 il probabile uso futuro. È 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 molto diverse da quelle di 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);

Questo sembra a posto: 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 proprietà_tipi 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
kevinsky