Come progettare un database per i campi definiti dall'utente?


145

I miei requisiti sono:

  • È necessario essere in grado di aggiungere dinamicamente campi definiti dall'utente di qualsiasi tipo di dati
  • Devi essere in grado di interrogare rapidamente gli UDF
  • È necessario essere in grado di eseguire calcoli sugli UDF in base al tipo di dati
  • Devi essere in grado di ordinare gli UDF in base al tipo di dati

Altre informazioni:

  • Cerco prestazioni principalmente
  • Esistono alcuni milioni di record master ai quali possono essere associati dati UDF
  • L'ultima volta che ho controllato, c'erano oltre 50 milioni di record UDF nel nostro database attuale
  • La maggior parte delle volte, un UDF è associato solo a poche migliaia di documenti Master, non a tutti
  • Gli UDF non vengono uniti o utilizzati come chiavi. Sono solo dati utilizzati per query o report

Opzioni:

  1. Crea una grande tabella con StringValue1, StringValue2 ... IntValue1, IntValue2, ... ecc. Odio questa idea, ma la prenderò in considerazione se qualcuno può dirmi che è meglio di altre idee e perché.

  2. Creare una tabella dinamica che aggiunge una nuova colonna su richiesta, se necessario. Inoltre, questa idea non mi piace poiché ritengo che le prestazioni sarebbero lente se non indicassi ogni colonna.

  3. Creare una singola tabella contenente UDFName, UDFDataType e Value. Quando viene aggiunto un nuovo UDF, genera una vista che estrae solo quei dati e li analizza in qualunque tipo sia specificato. Gli articoli che non soddisfano i criteri di analisi restituiscono NULL.

  4. Crea più tabelle UDF, una per tipo di dati. Quindi avremmo tabelle per UDFStrings, UDFDates, ecc. Probabilmente farebbe lo stesso di # 2 e genererebbe automaticamente una vista ogni volta che viene aggiunto un nuovo campo

  5. XML DataTypes? Non ho mai lavorato con questi prima ma li ho visti menzionati. Non sono sicuro che mi darebbero i risultati che desidero, soprattutto con le prestazioni.

  6. Qualcos'altro?


7
Martin Fowler raccomanda 2 (schema aggiornabile dall'utente) o 5 (LOB XML indicizzato): martinfowler.com/bliki/UserDefinedField.html
Neil McGuigan

Vedi anche la domanda StackOverflow sugli schemi di database dinamici .
FloverOwe

Risposte:


49

Se la prestazione è la preoccupazione principale, andrei con # 6 ... una tabella per UDF (davvero, questa è una variante di # 2). Questa risposta è specificamente adattata a questa situazione e alla descrizione della distribuzione dei dati e dei modelli di accesso descritti.

Professionisti:

  1. Poiché si indica che alcuni UDF hanno valori per una piccola porzione dell'insieme di dati complessivo, una tabella separata offre le migliori prestazioni poiché tale tabella sarà grande solo quanto deve essere per supportare l'UDF. Lo stesso vale per gli indici correlati.

  2. Puoi anche aumentare la velocità limitando la quantità di dati che devono essere elaborati per aggregazioni o altre trasformazioni. La suddivisione dei dati in più tabelle consente di eseguire alcune delle aggregazioni e altre analisi statistiche sui dati UDF, quindi unire quel risultato alla tabella principale tramite chiave esterna per ottenere gli attributi non aggregati.

  3. È possibile utilizzare nomi di tabelle / colonne che riflettano quali sono effettivamente i dati.

  4. Hai il controllo completo per utilizzare tipi di dati, verificare vincoli, valori predefiniti, ecc. Per definire i domini di dati. Non sottovalutare il colpo di prestazione derivante dalla conversione al volo del tipo di dati. Tali vincoli aiutano anche gli ottimizzatori di query RDBMS a sviluppare piani più efficaci.

  5. In caso di necessità di utilizzare chiavi esterne, l'integrità referenziale dichiarativa integrata viene raramente superata dall'applicazione di vincoli basata su trigger o a livello di applicazione.

Contro:

  1. Questo potrebbe creare molte tabelle. Applicare la separazione dello schema e / o una convenzione di denominazione allevia questo.

  2. Sono necessari più codici applicativi per far funzionare la definizione e la gestione dell'UDF. Mi aspetto che questo codice sia ancora meno necessario rispetto alle opzioni originali 1, 3 e 4.

Altre considerazioni:

  1. Se c'è qualcosa sulla natura dei dati che avrebbe senso raggruppare gli UDF, questo dovrebbe essere incoraggiato. In questo modo, tali elementi di dati possono essere combinati in un'unica tabella. Ad esempio, supponiamo che tu abbia UDF per colore, dimensioni e costi. La tendenza nei dati è che la maggior parte delle istanze di questi dati assomiglia

     'red', 'large', 45.03 

    piuttosto che

     NULL, 'medium', NULL

    In tal caso, non incorrerai in una notevole penalità di velocità combinando le 3 colonne in 1 tabella perché pochi valori sarebbero NULL ed eviti di creare altre 2 tabelle, che sono necessarie 2 join in meno quando devi accedere a tutte e 3 le colonne .

  2. Se colpisci un muro delle prestazioni da un UDF che è fortemente popolato e usato frequentemente, allora dovrebbe essere considerato per l'inclusione nella tabella principale.

  3. La progettazione di tabelle logiche può portarti a un certo punto, ma quando i conteggi dei record diventano davvero enormi, dovresti anche iniziare a guardare quali opzioni di partizionamento delle tabelle sono fornite dal tuo RDBMS preferito.


1
Liste di controllo! Nella battuta tra me e Phil, spero che non sia contro le regole.
Gunner L3510

Grazie, penso che farò qualche variazione di questo. La maggior parte dei nostri dati UDF proviene da campi di importazione non mappati che devono rimanere in giro solo a scopo di riferimento, quindi vorrei metterli in una tabella. Altri UDF sono definiti come necessari (non riesco a identificarli in anticipo .. di solito vengono creati quando cambiamo un processo o decidiamo di tenere traccia di qualcosa di speciale per alcuni mesi) e vengono comunemente utilizzati nelle query. Penso che creerò una tabella separata per ogni unità logica di questi valori.
Rachel

Sto lavorando con una tabella con UDF datato / con versione, utilizzo questo metodo, stackoverflow.com/a/123481/328968 , per ottenere gli ultimi valori.
Peter,

22

Ho scritto su questo problema molto . La soluzione più comune è l'antipattern Entity-Attribute-Value, che è simile a quello che descrivi nella tua opzione # 3. Evita questo disegno come la peste .

Quello che uso per questa soluzione quando ho bisogno di campi personalizzati veramente dinamici è archiviarli in un BLOB di XML, in modo da poter aggiungere nuovi campi in qualsiasi momento. Ma per renderlo più veloce, crea anche tabelle aggiuntive per ogni campo che devi cercare o ordinare (non hai una tabella per campo - solo una tabella per campo ricercabile ). Questo a volte viene chiamato un disegno di indice invertito.

Puoi leggere un interessante articolo del 2009 su questa soluzione qui: http://backchannel.org/blog/friendfeed-schemaless-mysql

Oppure puoi utilizzare un database orientato ai documenti, dove è previsto che tu abbia campi personalizzati per documento. Sceglierei Solr .


1
Puoi spiegare perché dovrei evitare l'opzione 3? Ho visto alcuni dei tuoi esempi, ma in realtà non sono gli stessi di quello che sto cercando di fare. Voglio semplicemente un posto dove archiviare dati extra, non un posto dove archiviare tutti gli attributi.
Rachel

2
Per i principianti, chi vorresti rendere un attributo NOT NULL? Come renderebbe un attributo UNICO senza rendere tutti gli attributi UNICI? Continua da lì. Finisci per scrivere il codice dell'applicazione per fornire funzionalità che RDBMS già ti fornisce, fino al punto di dover scrivere un qualche tipo di classe di mappatura per inserire semplicemente un record di entità logica e recuperarlo.
Bill Karwin,

2
La risposta breve è "non mescolare dati e metadati". La creazione di colonne varchar per fieldnameo tablenamesta memorizzando identificatori di metadati come stringhe di dati, e questo è l'inizio di molti problemi. Vedi anche en.wikipedia.org/wiki/Inner-platform_effect
Bill Karwin

2
@Thomas: nella progettazione dell'indice invertito, è possibile utilizzare soluzioni di schemi standard per tipi di dati e vincoli come UNIQUE e FOREIGN KEY. Quelli non funzionano affatto quando usi EAV. Concordo con le condivisioni di indici invertite con EAV come tratto non relazionale semplicemente perché supporta attributi diversi per riga, ma è un punto di compromesso.
Bill Karwin

2
@thitami, quello che ho imparato negli anni è che qualsiasi soluzione potrebbe essere quella giusta per la tua app. Anche EAV potrebbe essere la soluzione meno negativa per qualche app specifica. Non puoi scegliere una strategia di ottimizzazione senza conoscere le tue domande. Ogni tipo di ottimizzazione migliora determinate query a spese di altre query.
Bill Karwin,

10

Molto probabilmente creerei una tabella con la seguente struttura:

  • Nome varchar
  • Tipo varchar
  • NumberValue decimale
  • varchar StringValue
  • date DateValue

I tipi esatti ovviamente dipendono dalle tue esigenze (e ovviamente dai dbms che stai usando). Puoi anche usare il campo NumberValue (decimale) per int e booleani. Potresti aver bisogno anche di altri tipi.

È necessario un collegamento ai record master che possiedono il valore. Probabilmente è più semplice e veloce creare una tabella dei campi utente per ogni tabella principale e aggiungere una semplice chiave esterna. In questo modo è possibile filtrare i record master in base ai campi utente in modo semplice e rapido.

Potresti voler avere qualche tipo di informazione sui metadati. Quindi si finisce con il seguente:

Tabella UdfMetaData

  • int id
  • Nome varchar
  • Tipo varchar

Tabella MasterUdfValues

  • int Master_FK
  • int MetaData_FK
  • NumberValue decimale
  • varchar StringValue
  • date DateValue

Qualunque cosa tu faccia, non cambierei dinamicamente la struttura della tabella. È un incubo per la manutenzione. Inoltre non userei le strutture XML, sono troppo lente.


Mi piace la tua strategia e forse la opterò, ma nel 2017 sceglierai qualcosa di diverso? come json
maztt,

Nel nostro progetto, abbiamo implementato le nostre strutture dati che serializzano qualcosa di simile a JSON. È dotato di un'interfaccia typesave per leggere e scrivere i dati senza trasmettere e con una grande integrazione del linguaggio di programmazione. È davvero fantastico. Ha lo stesso problema di tutto questo tipo di "documenti" nei database. È difficile interrogare valori specifici e non può facilmente fare riferimento a dati al di fuori del "documento". A seconda dell'utilizzo, entrambi non rappresentano nemmeno un problema.
Stefan Steinegger

Oltre a ciò, quello che ho proposto nel 2011 è IMHO ancora una soluzione valida.
Stefan Steinegger

10

Sembra un problema che potrebbe essere risolto meglio con una soluzione non relazionale, come MongoDB o CouchDB.

Entrambi consentono l'espansione dinamica dello schema e al contempo ti consentono di mantenere l'integrità della tupla che cerchi.

Concordo con Bill Karwin, il modello EAV non è un approccio performante per te. L'uso di coppie nome-valore in un sistema relazionale non è intrinsecamente negativo, ma funziona bene solo quando la coppia nome-valore crea una tupla completa di informazioni. Quando lo usi ti costringe a ricostruire dinamicamente una tabella in fase di esecuzione, tutti i tipi di cose iniziano a diventare difficili. La query diventa un esercizio di manutenzione del perno o ti costringe a spingere la ricostruzione della tupla nel livello dell'oggetto.

Non è possibile determinare se un valore nullo o mancante è una voce valida o mancanza di voce senza incorporare le regole dello schema nel livello oggetto.

Perdi la capacità di gestire in modo efficiente il tuo schema. Un varchar di 100 caratteri è il tipo giusto per il campo "valore"? 200-caratteri? Dovrebbe essere nvarchar invece? Può essere un duro compromesso e uno che termina con la necessità di porre limiti artificiali alla natura dinamica del tuo set. Qualcosa del tipo "puoi avere solo x campi definiti dall'utente e ognuno può contenere solo y caratteri.

Con una soluzione orientata ai documenti, come MongoDB o CouchDB, gestisci tutti gli attributi associati a un utente all'interno di una singola tupla. Poiché i join non sono un problema, la vita è felice, poiché nessuno di questi due si comporta bene con i join, nonostante l'hype. I tuoi utenti possono definire tutti gli attributi che desiderano (o che consentirai) a lunghezze che non diventano difficili da gestire fino a raggiungere circa 4 MB.

Se si dispone di dati che richiedono integrità a livello di ACID, è possibile considerare la suddivisione della soluzione, con i dati ad alta integrità presenti nel database relazionale e i dati dinamici che vivono in un archivio non relazionale.


6

Anche se fornisci a un utente l'aggiunta di colonne personalizzate, non sarà necessariamente il caso che le query su tali colonne funzionino bene. Ci sono molti aspetti che vanno nella progettazione delle query che consentono loro di funzionare bene, il più importante dei quali è la specifica corretta su ciò che dovrebbe essere archiviato in primo luogo. Quindi, fondamentalmente, vuoi consentire agli utenti di creare schemi senza pensare alle specifiche ed essere in grado di ricavare rapidamente informazioni da quello schema? In tal caso, è improbabile che tale soluzione si ridimensioni bene soprattutto se si desidera consentire all'utente di eseguire analisi numeriche sui dati.

opzione 1

IMO questo approccio offre uno schema senza alcuna conoscenza del significato dello schema, che è una ricetta per il disastro e un incubo per i progettisti di report. Vale a dire, è necessario disporre dei metadati per sapere quale colonna memorizza quali dati. Se i metadati vengono incasinati, ha il potenziale per rendere flessibili i tuoi dati. Inoltre, semplifica l'inserimento di dati errati nella colonna sbagliata. ("Cosa? String1 contiene il nome di conventi? Pensavo fosse la droga preferita di Chalie Sheen.")

Opzione 3,4,5

IMO, i requisiti 2, 3 e 4 eliminano qualsiasi variazione di un EAV. Se devi interrogare, ordinare o fare calcoli su questi dati, un EAV è il sogno di Cthulhu e l'incubo del tuo team di sviluppo e DBA. Gli EAV creeranno un collo di bottiglia in termini di prestazioni e non ti daranno l'integrità dei dati di cui hai bisogno per ottenere rapidamente le informazioni che desideri. Le query si trasformeranno rapidamente in nodi gordiani a campi incrociati.

Opzione 2,6

Questo lascia davvero una scelta: raccogliere le specifiche e poi costruire lo schema.

Se il cliente desidera ottenere le migliori prestazioni sui dati che desidera archiviare, deve passare attraverso il processo di collaborazione con uno sviluppatore per comprendere le sue esigenze in modo che sia archiviato nel modo più efficiente possibile. Potrebbe essere comunque archiviato in una tabella separata dal resto delle tabelle con codice che crea dinamicamente un modulo basato sullo schema della tabella. Se si dispone di un database che consente di estendere le proprietà sulle colonne, è possibile utilizzarle anche per aiutare il generatore di moduli a utilizzare etichette, descrizioni comandi e così via in modo che sia sufficiente aggiungere lo schema. In entrambi i casi, per creare ed eseguire i report in modo efficiente, i dati devono essere archiviati correttamente. Se i dati in questione avranno molti null, alcuni database hanno la capacità di archiviare quel tipo di informazioni. Per esempio,

Se questo fosse solo un insieme di dati sui quali non si sarebbe dovuto fare alcuna analisi, filtraggio o ordinamento, direi che alcune variazioni di un EAV potrebbero fare il trucco. Tuttavia, dati i tuoi requisiti, la soluzione più efficiente sarà quella di ottenere le specifiche appropriate anche se memorizzi queste nuove colonne in tabelle separate e costruisci moduli dinamicamente da quelle tabelle.

Colonne sparse


5
  1. Crea più tabelle UDF, una per tipo di dati. Quindi avremmo tabelle per UDFStrings, UDFDates, ecc. Probabilmente farebbe lo stesso di # 2 e genererebbe automaticamente una vista ogni volta che viene aggiunto un nuovo campo

Secondo la mia ricerca, più tabelle basate sul tipo di dati non ti aiuteranno nelle prestazioni. Soprattutto se si dispone di dati in blocco, come record da 20K o 25K con oltre 50 UDF. Le prestazioni sono state le peggiori.

Dovresti andare con una singola tabella con più colonne come:

varchar Name
varchar Type
decimal NumberValue
varchar StringValue
date DateValue

Questo dovrebbe essere corretto e votato. La precedente risposta sul 2011 di Phil non è più un buon consiglio oggi 2016.
Yap Kai Lun Leon

Posso avere un semplice esempio di come eseguire tale processo in sql.?
Niroj,

Ci scusiamo per la risposta tardiva, ma vuoi la struttura del database per lo stesso. Non ti ho preso @Niroj. Puoi per favore spiegare in dettaglio come quello che vuoi.
Modifica appaltatore

4

Questa è una situazione problematica e nessuna delle soluzioni appare "giusta". Tuttavia, l'opzione 1 è probabilmente la migliore sia in termini di semplicità che in termini di prestazioni.

Questa è anche la soluzione utilizzata in alcune applicazioni aziendali commerciali.

MODIFICARE

un'altra opzione che è disponibile ora, ma non esisteva (o almeno non era matura) quando la domanda era originale era usare i campi json nel DB.

molti DB relazionali supportano ora campi basati su json (che possono includere un elenco dinamico di sottocampi) e consentono di eseguire query su di essi

Postgress

mysql


1
Odio l'idea di creare forse centinaia di colonne inutilizzate. Va contro ciò che ho imparato e letto sulla progettazione del database SQL. Al momento, abbiamo oltre 1300 diversi valori definiti dall'utente, sebbene molti di essi siano semplicemente duplicati di elementi esistenti che sono denominati in modo diverso.
Rachel,

1300 UDF diversi per una singola tabella? ogni utente ha la possibilità di aggiungere UDF o solo qualche tipo di power user?
Ophir Yoktan,

Fa parte del processo di importazione ... aggiunge tutti i dati non mappati a un campo definito dall'utente. Poiché nessuno impiega il tempo per mappare i dati non mappati sui campi UDF esistenti, ne crea solo di nuovi e nel corso degli anni ne sono stati aggiunti molti.
Rachel,

2

Ho avuto esperienza o 1, 3 e 4 e tutti finiscono per essere disordinati, con non è chiaro quali siano i dati o davvero complicati con una sorta di categorizzazione soft per suddividere i dati in tipi dinamici di record.

Sarei tentato di provare XML, dovresti essere in grado di applicare schemi contro il contenuto dell'xml per verificare la digitazione dei dati ecc. Nelle versioni più recenti di SQL Server è possibile indicizzare su campi XML, il che dovrebbe aiutare le prestazioni. (vedi http://blogs.technet.com/b/josebda/archive/2009/03/23/sql-server-2008-xml-indexing.aspx ) per esempio


Onestamente, non ho mai esaminato l'XML. Il principale svantaggio è che dovrei imparare come ha funzionato e come interrogarlo, e ho sentito che le prestazioni possono essere peggiori rispetto alle altre opzioni
Rachel,

1
Eviterei di usare xml per questo: può fare il lavoro, e in passato ho implementato qualcosa del genere in xml, ma le prestazioni sono peggiorate con l'aumentare delle strutture di dati e la complessità del codice era alta.
Kell

2

Se si utilizza SQL Server, non trascurare il tipo sqlvariant. È abbastanza veloce e dovrebbe fare il tuo lavoro. Altri database potrebbero avere qualcosa di simile.

I tipi di dati XML non sono così buoni per motivi di prestazioni. Se stai facendo calcoli sul server, devi costantemente deserializzarli.

L'opzione 1 suona male e sembra rozza, ma dal punto di vista delle prestazioni può essere la soluzione migliore. In precedenza ho creato tabelle con colonne denominate Field00-Field99 perché non puoi battere le prestazioni. Potrebbe essere necessario considerare anche le tue prestazioni INSERT, nel qual caso anche questa è la scelta giusta. Puoi sempre creare viste su questa tabella se vuoi che sia pulito!


Grazie, darò un'altra occhiata alle varianti SQL. La mia più grande preoccupazione è la prestazione e non sono sicuro di come gestirla, soprattutto se stiamo parlando di oltre 50 miglia di fila
Rachel,

Ho appena scoperto che sql_varients non può essere utilizzato con la clausola LIKE ... questo è un grande svantaggio per me. Ovviamente, se creo una vista per ogni UDF, allora potrei lanciarla nel tipo di dati appropriato basato su SQL_VARIANT_PROPERTY (valore, 'BaseType') ... comunque, sembra male per le prestazioni
Rachel

Puoi usare LIKE, ma devi prima lanciare il valore. LIKE funziona solo su varchars, quindi devi lanciare sql_variant su varchars. Fintanto che sai se il tuo UDF è un varchar (ad es. Perché il tipo è memorizzato altrove) puoi filtrare tutte le tue righe in varchars quindi eseguire il cast ed eseguire la tua query LIKE: ad es. seleziona * FROM MyTable dove variant_type = 'v' Cast (variant_value come varchar (max)) COME "Blah%" In questo modo, non stai convertendo ints e così via in stringhe che ti rallenterebbero.
Tim Rogers,

Avrei bisogno di eseguire alcuni test per vedere come sono le prestazioni, soprattutto con milioni di righe. Sei a conoscenza di articoli online sulle prestazioni che utilizzano sql_varients? Soprattutto con il casting e un numero molto elevato di dischi?
Rachel,


1

In passato ci sono riuscito molto bene usando nessuna di queste opzioni (opzione 6? :)).

Creo un modello con cui gli utenti possono giocare (memorizza come xml ed esporre tramite uno strumento di modellazione personalizzato) e dalle tabelle e dalle viste generate dal modello per unire le tabelle di base con le tabelle di dati definite dall'utente. Quindi ogni tipo avrebbe una tabella di base con dati core e una tabella utente con campi definiti dall'utente.

Prendi un documento come esempio: i campi tipici sarebbero nome, tipo, data, autore, ecc. Questo andrebbe nella tabella principale. Quindi gli utenti definiscono i propri tipi di documenti speciali con i propri campi, come contract_end_date, renewal_clause, blah blah blah. Per quel documento definito dall'utente ci sarebbe la tabella del documento principale, la tabella xcontract, unita su una chiave primaria comune (quindi anche la chiave primaria xcontracts è estranea alla chiave primaria della tabella principale). Quindi vorrei generare una vista per avvolgere queste due tabelle. Le prestazioni durante le query sono state veloci. regole di business aggiuntive possono anche essere incorporate nelle viste. Questo ha funzionato davvero bene per me.


1

Il nostro database alimenta un'app SaaS (software di helpdesk) in cui gli utenti dispongono di oltre 7k "campi personalizzati". Usiamo un approccio combinato:

  1. (EntityID, FieldID, Value)tabella per la ricerca dei dati
  2. un campo JSON nella entitiestabella, che contiene tutti i valori di entità, utilizzato per visualizzare i dati. (in questo modo non è necessario un milione di JOIN per ottenere i valori).

Potresti ulteriormente dividere il numero 1 per avere una "tabella per tipo di dati" come suggerisce questa risposta , in questo modo puoi anche indicizzare i tuoi UDF.

PS Coppia di parole per difendere l'approccio "Entità-Attributo-Valore" che tutti continuano a colpire. Abbiamo usato # 1 senza # 2 per decenni e ha funzionato bene. A volte è una decisione aziendale. Hai tempo per riscrivere la tua app e ridisegnare il db o puoi buttare un paio di dollari sui server cloud, che al giorno d'oggi sono davvero economici? A proposito, quando stavamo usando l'approccio n. 1, il nostro DB conteneva milioni di entità, accessibili da centinaia di migliaia di utenti, e un server db dual-core da 16 GB stava andando bene


Ciao @Alex, ho riscontrato un problema simile. Se ho capito bene hai: 1) una custom_fieldstabella che memorizza valori come 1 => last_concert_year, 2 => band, 3 => musice poi una custom_fields_valuestabella con valori 001, 1, 1976 002, 1, 1977 003, 2, Iron Maiden003, 3 , Metal Spero che l'esempio abbia senso per te e scusa per la formattazione!
thitami,

@thitami non esattamente. Seguendo il tuo esempio: ho una bandstabella con una riga, 1,'Iron Maiden'quindi custom_fieldscon le righe e 1,'concert_year' | 2,'music'poi custom_fields_valuescon le righe1,1,'1977'|1,2,'metal'
Alex

0

Nei commenti ti ho visto dire che i campi UDF devono scaricare i dati importati che non sono mappati correttamente dall'utente.

Forse un'altra opzione è quella di tracciare il numero di UDF creati da ciascun utente e costringerli a riutilizzare i campi dicendo che possono usare 6 (o altri limiti ugualmente casuali) in cima ai campi personalizzati.

Quando ti trovi di fronte a un problema di strutturazione del database come questo, spesso è meglio tornare alla progettazione di base dell'applicazione (sistema di importazione nel tuo caso) e porre qualche limitazione in più.

Ora quello che vorrei fare è l'opzione 4 (EDIT) con l'aggiunta di un collegamento agli utenti:

general_data_table
id
...


udfs_linked_table
id
general_data_id
udf_id


udfs_table
id
name
type
owner_id --> Use this to filter for the current user and limit their UDFs
string_link_id --> link table for string fields
int_link_id
type_link_id

Ora assicurati di creare viste per ottimizzare le prestazioni e ottenere gli indici corretti. Questo livello di normalizzazione riduce l'ingombro del DB, ma l'applicazione è più complessa.


0

Consiglierei il n. 4 poiché questo tipo di sistema è stato utilizzato in Magento, che è una piattaforma CMS di e-commerce altamente accreditata. Utilizzare una singola tabella per definire i campi personalizzati utilizzando le colonne fieldId & label . Quindi, disporre di tabelle separate per ciascun tipo di dati e all'interno di ciascuna di tali tabelle è presente un indice che indicizza per fieldId e le colonne del valore del tipo di dati . Quindi, nelle tue query, usa qualcosa come:

SELECT *
FROM FieldValues_Text
WHERE fieldId IN (
    SELECT fieldId FROM Fields WHERE userId=@userId
)
AND value LIKE '%' + @search + '%'

Questo a mio avviso garantirà le migliori prestazioni possibili per i tipi definiti dall'utente.

Nella mia esperienza, ho lavorato su diversi siti Web Magento che servono milioni di utenti al mese, ospitano migliaia di prodotti con attributi di prodotto personalizzati e il database gestisce facilmente il carico di lavoro, anche per i report.

Per i report, è possibile utilizzare PIVOTper convertire i valori delle etichette della tabella Fields in nomi di colonna, quindi ruotare i risultati della query da ciascuna tabella dei tipi di dati in quelle colonne pivotate.

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.