tabelle autoreferenziali, buone o cattive? [chiuso]

32

Rappresentando le posizioni geografiche all'interno di un'applicazione, la progettazione del modello di dati sottostante suggerisce due opzioni chiare (o forse più?).

Una tabella con una colonna parent_id di riferimento automatico uk - london (id genitore di Londra = id del Regno Unito)

o due tabelle, con una relazione uno a molti utilizzando una chiave esterna.

La mia preferenza è per una tabella di self-refercing in quanto consente facilmente di estendersi in tutte le sottoregioni necessarie.

IN GENERALE le persone si allontanano dalle tabelle autoreferenziali, o sono A-OK?

    
posta NimChimpsky 30.11.2012 - 14:08
fonte

3 risposte

36

Niente di sbagliato con le tabelle autoreferenziali.

È il modello di progettazione di database comune per gerarchie nidificate in profondità (infinito?).

    
risposta data 30.11.2012 - 14:26
fonte
4

Necromancing.
La risposta corretta è: dipende da quale motore di database e su quale strumento di gestione.

Facciamo un esempio:
Abbiamo una tabella dei rapporti,
e un report può avere un genitore (menupoint, come categoria),
e quel genitore può avere un genitore (ad es. centro di profitto),
e così via all'infinito.

L'esempio più semplice di una relazione ricorsiva standard, come con qualsiasi entità / gerarchia autoreferenziale.

La tabella SQL Server risultante è:

IF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'dbo.FK_T_FMS_Reports_T_FMS_Reports') AND parent_object_id = OBJECT_ID(N'dbo.T_FMS_Reports'))
ALTER TABLE dbo.T_FMS_Reports DROP CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports
GO

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.T_FMS_Reports') AND type in (N'U'))
DROP TABLE dbo.T_FMS_Reports 
GO



CREATE TABLE dbo.T_FMS_Reports 
( 
     RE_UID uniqueidentifier NOT NULL 
    ,RE_RE_UID uniqueidentifier NULL 
    ,RE_Text nvarchar(255) NULL 
    ,RE_Link nvarchar(400) NULL 
    ,RE_Sort int NOT NULL 
    ,RE_Status int NOT NULL 
    ,PRIMARY KEY CLUSTERED ( RE_UID ) 
); 

GO

ALTER TABLE dbo.T_FMS_Reports  WITH CHECK ADD  CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports FOREIGN KEY(RE_RE_UID) 
REFERENCES dbo.T_FMS_Reports (RE_UID) 
-- ON DELETE CASCADE -- here, MS-SQL has a problem 
GO

ALTER TABLE dbo.T_FMS_Reports CHECK CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports 
GO

Ma hai un problema:
Quando devi eliminare un menupoint con tutti i suoi sottomenuppi, NON PUO impostare delete-cascade, perché Microsoft SQL-Server non supporta le eliminazioni in cascata ricorsive (d'altra parte , PostGreSQL lo fa, mentre a MySQL non piace affatto questo tipo di struttura della tabella, perché non supporta le CTE ricorsive).

Quindi esploderai con cancellazione / integrità / funzionalità, rendendo obbligatorio implementare tale funzionalità nel tuo codice o in una stored procedure (se il tuo RDBMS supporta stored procedure).

Questo senza dubbio farà esplodere qualsiasi tipo di importazione / esportazione dinamica dei dati completamente automatica, perché non puoi semplicemente eseguire un'istruzione delete per tutte le tabelle in base a relazioni a chiave esterna (non autoreferenziale), né puoi fare una semplice selezione * e crea un inserto per ogni riga in un ordine arbitrario.

Ad esempio, quando si crea uno script INSERT utilizzando SSMS, SSMS non otterrà la chiave esterna e quindi crea effettivamente istruzioni di inserimento che inseriranno entrys con dipendenze, prima che inserisca il parent della dipendenza, che fallirà con un errore, perché la chiave esterna è a posto.

Tuttavia, su sistemi di gestione di database adeguati (come PostgreSQL), con strumenti adeguati, questo non dovrebbe essere un problema. Basta capire che solo perché paghi molto per il tuo RDBMS (sto guardando te, Microsoft; Oracle =?), E / o la sua cintura degli attrezzi, non significa che sia programmato correttamente. E nemmeno OpenSource (ad esempio MySQL) ti rende immune a tali meravigliose minuzie.

Il diavolo è nei dettagli, come dice il vecchio proverbio.

Ora, non che non potresti lavorare su questi problemi, ma non lo raccomanderei davvero, se il tuo sistema sarà complesso (ad esempio più di 200 tavoli).
Inoltre, in un normale contesto commerciale (come interpretato da Dilbert), non ti verrà dato quel tempo.

Un approccio molto migliore, anche se più difficile, sarebbe un tavolo di chiusura.
Ciò avrebbe il vantaggio aggiuntivo che funzioni anche su MySQL.
Una volta implementata la funzionalità di chiusura una volta, la farai funzionare in altri posti in un tempo quasi inesistente.

    
risposta data 15.09.2015 - 10:47
fonte
1

È una buona idea se la relazione sia effettivamente gerarchica e non una relazione di rete (ad esempio una distinta base è una relazione di rete, non una gerarchia).

Può essere lento interrogare. Per velocizzare le cose, puoi utilizzare una tabella di chiusura.

link

    
risposta data 29.06.2013 - 21:41
fonte

Leggi altre domande sui tag