|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Jan 2001
Città: Provincia di Milano __Xbox Live!: KillersGemini __PSN: Gemini_KKlan
Messaggi: 6735
|
[SQL] toglietemi un dubbio sulle relazioni
Ciao a tutti,
premetto che la mia conoscenza di DB ed SQL è limitata a piccoli progetti, composti nello specifico da qualche centinania di record e poco meno di 50 tabelle. Il mio dubbio è il seguente, quando e quanto conviene strutturare una relazione 1 a molti tra 1 tabella padre e N tabelle figlio? parlo non solo a livello "tecnico", ma soprattutto a livello pratico e prestazionale. Mi spiego meglio, magari con un esempio in genere la tabella padre è una tabella di prodotto, organizzata così Codice:
T_PADRE id_prodotto nome_prodotto tipologia_id colore_id marca_id forma_id T_TIPO tipologia_id descr T_COLORE colore_id descr T_MARCA marca_id descr T_FORMA forma_id descr ora mi chiedo, quanto è giusto far così piuttosto che inserire nella tabella padre (al posto dell'id relazionato con la tabella figlio) la descrizione stessa del campo interessato? il dubbio nasce dal fatto, che spesso viene richiesto l'inserimento del campo "altro" (relativo ai campi relazionati) il che mi obbliga a soluzioni che ritengo poco pratiche (a livello di codice e di sql). Perdonate il mio linguaggio "poco tecnico", ma in materia ho poca esperienza grazie |
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Normalizzare, come hai fatto tu, è una buona cosa, per i seguenti motivi:
1) mantiene consistente il db (visto che la scelta dei valori è limitata soltanto a quelli presente nelle tabelle "foreign"; questo è il gergo tecnico); 2) compatta i dati facendo occupare meno spazio (molto meglio inserire 100 volte l'intero 1234567890 che "Giovinco"); 3) migliora le prestazioni nelle ricerche (meno spazio si traduce in PIU' record presenti in una singola pagina del database, quindi meno accessi al disco; inoltre gli indici sugli id occupano molto meno spazio, e idem per i medesimi campi indicizzati delle tabelle "foreign"). Inoltre se hai tabelle con troppi campi puoi ottimizzare la velocità di accesso alla tabella "spezzandola" in due tabelle: nella prima (quella principale) metti tutti i campi per cui per un motivo o per un altro puoi fare qualche ricerca su di essi; nella seconda metti tutti gli altri campi "accessori" che recuperi esclusivamente a fini di visualizzazione o stampa. In questo modo tutte le query che fai sulla prima tabella verranno velocizzate perché, come spiegato nel punto 3, una pagina del db conterrà molti più record e gli accessi al disco saranno di meno. Questo principio l'ho applicato di recente a una tabella con un paio di milioni di record, e una query è passata da 8 a 6 secondi. Tanto per fare un esempio.
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
|
|
|
|
|
#3 | |
|
Senior Member
Iscritto dal: Aug 2005
Messaggi: 579
|
Quote:
Per quanto riguarda dati "accessori" è sempre un problema il fatto che siano poco standardizzabili (ci ho scritto una tesi su queste faccende). Solitamente si tende a tenere così nel limbo tali dati per poi standardizzarli e formalizzarli non appena possibile... tra l'altro calcoli statistici dicono che in caso di rarità di questi dati costa di più standardizzarli e/o creare una struttura software di gestione apposita che nemmeno gestirli così, grezzi... Per quanto riguarda la tecnica proposta da cdimauro se ho ben capito si tratta di "spostare" dati tra due tabelle identiche in base alla loro località temporale. Non sono molto d'accordo, perchè è una pratica poco ortodossa... ma si sa che ogni metodo rude è buono nell'informatica. Tuttavia piuttosto che un metodo così "faccendiero" preferirei costruire una struttura software (oggetti serializzati) che contengono i dati acceduti più frequentemente in modo che avrei il massimo delle prestazioni, non facendo riferimento ogni volta a qualcosa salvato sul disco (DataBase) ma avrei direttamente i miei dati in RAM e in caso di reboot del sistema o chiusura del software essendo l'oggetto serializzabile può essere comodamente salvato e ricaricato così com'è da disco. (Ovviamente va usata una struttura dati apposita che richiede con ogni probabilità un linguaggio ad oggetti, non a caso io ho parlato di oggetto). |
|
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Forse non sono stato molto chiaro. La mia idea è di dividere una tabella in due tabelle legate da relazione 1:1, lasciando sulla prima i dati usati più frequentemente per le ricerche, mentre sulla seconda quelli "accessori".
L'esempio a cui mi riferivo lo riporto qui. Ecco la tabella originale: Codice:
CREATE TABLE Formats (
ID INTEGER NOT NULL AUTO_INCREMENT,
ItemID INTEGER NOT NULL,
SubProductTypeID INTEGER NOT NULL,
Language SET('it','en','fr','de','sv','zh','cs','da','nl','fi','hu','ja','ko','no','pl','pt','ru','sk','es','tr') NOT NULL,
StorageURI LONGBLOB,
Digest VARCHAR(40) NOT NULL DEFAULT '',
CONSTRAINT pk_Formats PRIMARY KEY (ID),
CONSTRAINT fk_Formats_ItemID FOREIGN KEY (ItemID) REFERENCES Items (ID) ON DELETE CASCADE,
CONSTRAINT fk_Formats_SubProductType FOREIGN KEY (SubProductTypeID) REFERENCES SubProductTypes (ID) ON DELETE CASCADE
) ENGINE = InnoDB;
Codice:
CREATE TABLE Formats (
ID INTEGER NOT NULL AUTO_INCREMENT,
ItemID INTEGER NOT NULL,
SubProductTypeID INTEGER NOT NULL,
Language SET('it','en','fr','de','sv','zh','cs','da','nl','fi','hu','ja','ko','no','pl','pt','ru','sk','es','tr') NOT NULL,
CONSTRAINT pk_Formats PRIMARY KEY (ID),
CONSTRAINT fk_Formats_ItemID FOREIGN KEY (ItemID) REFERENCES Items (ID) ON DELETE CASCADE,
CONSTRAINT fk_Formats_SubProductType FOREIGN KEY (SubProductTypeID) REFERENCES SubProductTypes (ID) ON DELETE CASCADE
) ENGINE = InnoDB;
CREATE TABLE FormatsExtras (
FormatID INTEGER NOT NULL,
StorageURI LONGBLOB,
Digest VARCHAR(40) NOT NULL DEFAULT '',
CONSTRAINT fk_FormatsExtras_FormatID FOREIGN KEY (FormatID) REFERENCES Formats (ID) ON DELETE CASCADE
) ENGINE = InnoDB;
Il risultato è che le query che eseguo molto spesso sono state velocizzate, al costo di un leggero aumento dei tempi di calcolo quando servono i dati presenti nella seconda tabella, ossia raramente.
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
|
|
|
|
|
#5 | |
|
Senior Member
Iscritto dal: Aug 2005
Messaggi: 579
|
Quote:
|
|
|
|
|
|
|
#6 |
|
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Io non salvo soltanto alcuni "prodotti" sulla seconda tabella: li salvo tutti.
Cioé, se ho 100 record nella prima tabella, ho sempre 100 record anche nella seconda, dove ogni record della prima è collegato a uno e un solo record nella seconda (relazione 1:1). Complessivamente non ho meno dati (anzi, ne ho leggermente di più perché la collona ID della prima tabella è duplicata anche nella seconda), ma semplicemente ho spostato delle colonne dalla prima alla seconda tabella. Il vantaggio è che questo spostamento mi permette di compattare molto di più i dati della prima tabella, rendendo le operazioni di ricerca molto più veloci (perché vengono lette meno pagine dal db, e quindi eseguendo meno accesso al disco).
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
|
|
|
|
|
#7 | |
|
Senior Member
Iscritto dal: Aug 2005
Messaggi: 579
|
Quote:
E la soluzione rimane pur sempre poco ortodossa e aderente agli standard. Inoltre comporta anche una modifica alla composizione delle query facendo salire a livello software tale modifica... tanto vale implementare a livello software la soluzione che ho proposto io con relativa politica di aggiornamento e sostituzione. |
|
|
|
|
|
|
#8 | ||||
|
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Quote:
Ti assicuro che la mia soluzione funziona bene, specialmente con tanti dati. Quote:
Quote:
Quote:
Inoltre non sempre è fattibile / utile, perché mi costringe a introdurre in un server centrale delle API per forzare il flush o l'update degli oggetti, visto che non sono l'unico ad accedere al DB per eseguire modifiche. API che ovviamente devono usare tutte le applicazioni. Immagino che il modello a cui ti riferisci sia quello di hibernate, ma per quel che ci faccio con le mie applicazioni è più costoso a livello implementativo e meno performante. My 2 cents.
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys Ultima modifica di cdimauro : 16-10-2008 alle 22:59. |
||||
|
|
|
|
|
#9 | |
|
Senior Member
Iscritto dal: Aug 2005
Messaggi: 579
|
Quote:
La progettazione delle basi di dati in teoria esula del tutto dal problema dell'ottimizzazione dei tempi di accesso, cosa che si da per scontato faccia bene il DB. In ogni caso non è comunque ottimale modificare le query sql da quelle concettualmente corrette (da manuale) anche per una semplice join. Inoltre la progettazione di una soluzione come proposta da me andrebbe anzi benissimo proprio una struttura distribuita in cui ogni server periferico aggiorna i propri dati interni (tenendoli su ram in fase di esecuzione e non chiedendoli via rete, e salvandoli su disco serializzati quando se ne ha bisogno) e tiene una copia che si presume sia il più coerente possibile... insomma tipo le cache. In caso di modifiche queste sarebbero effettuate nella maniera canonica, anche perchè in ogni caso vanno aggiornate entrambe le tabelle. Poi, per carità, io ti parlo delle soluzioni da manuale, poi è ovvio che nella pratica ci sono 1000 altre problematiche che rendono quelle soluzioni poco praticabili, ma l'errore sta nel fatto di assumere come ottime in assoluto soluzioni locali ad uno specifico contesto e riproporle altrove. |
|
|
|
|
|
|
#10 | |||||
|
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Quote:
E' vero che sulla carta i db dovrebbero memorizzare dati e basta, ma li devono rendere accessibili per quanto serve all'applicazione. Per questo scegliamo accuratamente anche dove andare a piazzare gli indici. Altrimenti lasceremmo al db l'onere e l'onore di organizzarsi i dati come meglio crede. Quote:
Quote:
Quote:
Quote:
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
|||||
|
|
|
|
|
#11 |
|
Senior Member
Iscritto dal: Jan 2001
Città: Provincia di Milano __Xbox Live!: KillersGemini __PSN: Gemini_KKlan
Messaggi: 6735
|
Grazie a tutti e due per la grande quantità di informazioni a rugardo
credo d'aver capito che, la strada percorsa è giusta (anche se ogni tanto non sopporto di dover definire relazioni di inner e left join ... ma ci si abitua molto in fretta); mi resta sempre e cmq il problema pratico dei dati non standardizzati e presenti nelle tabelle accessorie. per dirla con un esempio pratico (che mi capita spesso) i possibili prodotti (che per ipotesi si chiamano "prodotto_1", "prodotto_2", "prodotto_n") hanno sicuramente 2 colori (in RGB, per comodità "FFFFFF", "000000"); però può capitare che qualcuno faccia un colore ad-hoc che per quel prodotto non è disponibile in origine (diventa quindi impossibile gestire il campo con una relazione, ma devo lasciare all'utente finale la possibilità di inserire un colore "a mano") il mio problema è: se il campo colore_id nella tabella prodotti è un relazione con la tabella colore; è impossibile inserire una stringa? e trovo impossibile gestire una "seconda relazione" con una tabella non standardizzata (che poi dovrò farla compilare dall'utenza finale, il che renderebbe il dato non certificato), non saprei come capire, lato software, a quale delle due tabelle devo relazionarmi, devo necessariamente usare un nuovo campo "altro" in più per ogni campo relazionato? una nuova tabella (usando forse la soluzione di cdimauro?) è questo il mio principale dubbio grazie |
|
|
|
|
|
#12 | ||
|
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Quote:
Quote:
Per risolvere il tuo problema non dovresti usare un id per il colore, ma memorizzare direttamente la stringa che lo rappresenta. Al più la tabella dei colori la puoi usare come look-up, per fornire all'utente un elenco da cui selezionare velocemente un colore.
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
||
|
|
|
|
|
#13 | |
|
Senior Member
Iscritto dal: Jan 2001
Città: Provincia di Milano __Xbox Live!: KillersGemini __PSN: Gemini_KKlan
Messaggi: 6735
|
Quote:
era la soluzione che volevo adottare, ma non so se percorrere questa strada o quella delle refenrenziazioni + secondo capo di testo ... se tecnicamente è valida, forse conviene usare quella delle tabelle look-up? |
|
|
|
|
|
|
#14 |
|
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Per il tipo di informazione che stai trattando, ti consiglierei di usare il mio suggerimento.
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
|
|
|
|
|
#15 | |
|
Senior Member
Iscritto dal: Jan 2001
Città: Provincia di Milano __Xbox Live!: KillersGemini __PSN: Gemini_KKlan
Messaggi: 6735
|
Quote:
grazie a tutti per le info |
|
|
|
|
|
|
#16 | |||||
|
Senior Member
Iscritto dal: Aug 2005
Messaggi: 579
|
Quote:
Quote:
Quote:
Quote:
Quote:
|
|||||
|
|
|
|
|
#17 | |||
|
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Quote:
Questa è una cosa che può decidere soltanto il progettista del db, in base al carico di lavoro che è previsto (o che si è valutato anche in un secondo momento): non può farlo il db autonomamente (tante volte m'è pure capitato di dover correggere la query plan perché l'ottimizzatore aveva cannato clamorosamente). Quote:
Quote:
Io invece ricevo spesso richieste di dati diversi, per cui il caching è sostanzialmente inutile a fronte di una notevole complessità del codice. Non v'è dubbio che in condizioni diverse il tuo approccio sarebbe preferibile. Tra l'altro faccio già caching "massivo" per alcune tabelle che vengono usate molto spesso (e sono abbastanza piccole): le precarico e lavoro esclusivamente in memoria; quando i dati cambiano oppure a intervalli di tempo predefiniti eseguo il refresh delle cache. Per tutto il resto, dove l'accesso ai dati è quasi causale, ho preferito adottare la politica della query per ogni richiesta, come dicevo prima.
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
|||
|
|
|
|
|
#18 |
|
Messaggi: n/a
|
La normalizzazione come tu l'hai posta è giusta ovviamente.
I concetti stessi di "piegare" o "rompere" le regole di normalizzazione quando necessario (tempi di sviluppo, praticità, ecc.) vanno benissimo quando fatti con coscienza. Il discorso del campo "altro" che hai esposto è verissimo e a chiunque (pure a me) è capitato spesso di dovervi far fronte. Purtroppo in questo caso, a mio modo di vedere, non è tanto un problema di normalizzazione, di codice ecc. quanto un problema a livello più alto ovvero di "architettura dell'informazione". In una categorizzazione precisa ed esauriente voci come "altro, varie, miscellanea" ecc. non dovrebbero esistere in quanto sono solo un calderone di ripiego per una scarsa ottimizzazione dell'architettura informativa del proprio sistema. Da qui quindi la derivazione di tutti i problemi di sorta durate la fase di normalizzazione di un DB e non solo. Il mio consiglio è quindi prima di tutto, se possibile, cercare di eliminare situazioni "pericolose" come queste. Nel caso ove non fosse possibile allora credo stia di caso in caso decidere come meglio procedere. |
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 00:31.




















