2009-11-16 13 views
13

Ogni tutorial che ho visto su modelli di database multi-tenant ti dice di mettere la TenantID in ogni singola tabella:DB multi-tenant: perché inserire una colonna TenantID in ogni tabella?

zoos 
------- 
id 
zoo_name 
tenant_id 

animals 
------- 
id 
zoo_id 
animal_name 
tenant_id 

Tuttavia, questo sembra ridondante a me. Perché non aggiungere la colonna tenant_id alla sola tabella zoos e sfruttare la relazione di chiave esterna tra zoos e animals?

si fa ad aggiungere tenant_id ad ogni tavolo solo per mantenere i join da troppo pazzo? È una salvaguardia contro i bug? Una considerazione prestazionale?

+1

Ci sono considerazioni sulla progettazione di database multi-tenant, leggere su un articolo MSDN: [Multi-Tenant Data Architecture] (http://msdn.microsoft.com/en-us/library/aa479086.aspx) In breve ci sono diversi approcci, ed è un continuum di scelte e conseguenze. Prendere una decisione informata in base ai requisiti. –

risposta

8

Se disponevo di tenantID nella parte superiore della gerarchia (ad esempio a livello di zoo), è necessario prendere in considerazione diversi aspetti.

  1. Il vertice della gerarchia non potrà mai cambiare, ad esempio se è necessario aggiungere un nodo sul legno della croce sopra del livello zoo (ad esempio le regioni -> Zoo -> animali) allora sarà forzare una ri-org ogni tempo.
  2. Per determinate query, si saranno costretti a iniziare al vertice della gerarchia, cioè mi invia un elenco di tutti gli animali disponibili vi costringerà a iniziare in cima all'albero
  3. Perché non usare gli schemi? Ogni inquilino è isolato all'interno del proprio schema. Questo separerà anche i set di dati.
5

La prima cosa che viene in mente è che è più lento cercare animals > zoos > tenants che semplicemente animals > tenants. E molto probabilmente questa è una ricerca che farai spesso (ad esempio, "ottieni tutti gli animali per un determinato inquilino, indipendentemente dallo zoo").

Per applicazioni di piccole e medie dimensioni è possibile ottenere una struttura più normalizzata, ma per motivi di efficienza, è necessario utilizzare dati estranei (e in generale le applicazioni di multi-tenancy non sono piccole). Assicurati solo che non vada "fuori sincrono", il che è un rischio derivante dall'avere dati ridondanti.

Per rispondere al tuo ultimo paragrafo, il motivo è la prestazione, pura e semplice. Le unioni non sono niente male; ti aiutano a conservare un pezzo di dati in un posto anziché in tre. Non è assolutamente da evitare bug. L'aggiunta di un campo tenant_id a più tabelle aumenterà il rischio di bug (anche se per un ID che non cambia mai, non sarebbe tanto un problema).

+1

-1. Memorizzare l'ID tenant solo nel tavolo dello zoo non è più "normalizzato". Memorizzarlo in ogni tabella come chiave esterna non è estraneo; questo è quello che * dovresti * fare con le chiavi esterne. –

+0

Sì, lo è. Più un database è normalizzato, minore è la ridondanza che ha. Penso che sarete d'accordo sul fatto che la memorizzazione di un ID in più punti sia ridondante. Non ho mai detto che i campi sarebbero chiavi esterne di prima classe che gestiscono la coerenza dei dati, ma anche se fossero in grado di ridurre le prestazioni a causa di controlli aggiuntivi. La domanda era di spiegare un motivo per cui il campo è stato aggiunto a più tabelle, cosa che penso di aver fatto. Quindi direi che il tuo -1 è ingiustificato. – Blixt

+1

Le chiavi esterne non sono ridondanti. Sono una caratteristica centrale e distintiva del modello relazionale. In un'architettura a schemi multi-tenant condivisa, tutte le chiavi esterne sono chiavi composte composte da tenant_id e qualcos'altro. Quell'inquilino è l'unica cosa che distingue le righe di un inquilino dalle file di ogni altro inquilino. Lascia l'id titolare fuori da una tabella e devi anche disabilitare inserimenti, aggiornamenti ed eliminazioni. (Pensaci per un minuto.) –

8

È lì per comodità e prestazioni: in termini di normalizzazione hai assolutamente ragione, deve solo entrare in alto. Il problema diventa allora che per ottenere alcuni dati (ad esempio zoo -> animale -> cibo -> fornitore) devi avere join orribilmente complessi su quelle che sono domande molto semplici.

Quindi nel mondo reale si deve scendere a compromessi - la domanda diventa quindi dove e fino a che punto.

veda questo articolo Maybe Normalizing Isn't Normal - e la sua conclusione:

Come il vecchio adagio va, normalizzare fino a soffrire, denormalizzare finché non funziona

come un luogo per iniziare ad esplorare il soggetto

+0

A rischio di iniziare una guerra religiosa nerd, non posso fare a meno di chiedermi se questo non è un esempio di dove una chiave naturale sarebbe utile in forma. Se la tua app multi-tenant è partizionata per nome di dominio e imposti il ​​tenant_id al nome del dominio, puoi ridurre anche i join in questo modo. – Paul

+0

Non ridurrà i join - hai ancora il problema di includere la chiave a più livelli (notoriamente cattiva) o di join complessi (anche notoriamente cattivi) e indipendentemente dai tasti naturali quasi sempre ritorni e mordi (-: – Murph

+1

- 1. Se normalizzi una multi-tenant, una relazione condivisa con 3NF o 5NF, finirai con l'identificativo del titolare in ogni tabella. –

14

Se una delle considerazioni chiave relative alla progettazione è la sicurezza, in particolare, un client non può in alcun modo no come quando accede ai dati di un altro cliente, quindi, a seconda su come si implementa questa sicurezza, potrebbe essere necessario incollare la colonna di qualificazione in ogni tabella. Una di queste tattiche descritte con here richiede la creazione di una vista su ogni tabella; supponendo che ogni tabella contenga una colonna tenantId, se opportunamente configurata ogni vista potrebbe contenere una clausola "WHERE tenantId = SUSER_SID()" (e ovviamente si configura il database in modo che i client possano accedere solo alle viste).

Un altro fattore (come nel mio lavoro corrente) è il caricamento dei dati di magazzino (ETL). Le tabelle sono partizionate su tenantId (usiamo il partizionamento delle tabelle, ma anche le viste partizionate funzionerebbero) ei dati possono essere facilmente caricati o scaricati per un client senza incidere seriamente su nessun altro client.

Ma come sempre, c'è un sacco di "dipende" coinvolti. Se non c'è una necessità chiara e presente, e una probabilità molto bassa di necessità futura, quindi normalizzare quella colonna. Basta rendersi conto che è più un dispositivo di implementazione fisica che di progettazione di database concettuale o logica.

0

Beh, Bob potrebbe possedere una giraffa nello zoo numero 1, mentre Joe potrebbe possedere un leone nello stesso zoo. Non dovrebbero guardare i dati degli altri.

0

Il motivo N1 è per la sicurezza.

La sicurezza deve essere un concetto forte nell'applicazione multi-tenant.

Supponiamo che tu conceda a un utente la possibilità di modificare un animale. Si crea un modulo con una selezione che mostra lo zoo per l'attuale inquilino. Cosa succede se l'utente ha hackerato il modulo e ha passato uno zoo di un altro inquilino?

L'animale verrà spostato in un altro zoo di un altro inquilino !!

Questo è un vero dolore in un'app multi-tenant!

+0

Potresti fare controlli sul lato server per assicurarti che l'utente abbia i diritti su quell'ID Dovresti farlo a prescindere dal design del db, ma ho capito il tuo punto: –

+2

Cosa succede se l'utente infila il modulo e fornisce l'id di un animale che appartiene ad un altro titolare? Cosa succede se l'utente fa il "mio profilo" "pagina per fornire l'id del super-account-amministratore? Semplicemente non ci si può fidare dell'input dell'utente - che si applica a qualsiasi sistema in cui gli utenti hanno permessi diversi, non solo multi-tenancy. –

Problemi correlati