Newsgroup: it.comp.software.database
Titolo: Consiglio struttura DB

Salve,
avrei bisogno di un consiglio su come strutturare un DB. Cerco di
spiegarmi perche` e` un po' complicato, quindi il post e` un po' lungo. :)
Io ho una lista di riviste (quindi periodici) di cui voglio memorizzare
diverse informazioni.
Poi ho una lista di "abbonati" che vogliono sapere quando e` uscito il
nuovo numero delle riviste a cui sono abbonati.
Inoltre dalla parte opposta ho il venditore che deve poter aggiornare il
db scrivendoci dentro per ogni numero uscito di ogni rivista quale e` il
prezzo di copertina, quanto l'ha pagata e dove l'ha comprata (e magari
anche a chi l'ha venduta).
Quello che interessa a me e` dove mettere il numero della rivista e il suo
prezzo di copertina.
Avevo pensato a una struttura come
table rivista (
	id,
	...
	nome,
	numero,
	prezzo,
	...
)
table abbonato (
	id,
	nome,
	...
)
table abbonamento (
	id,
	idabbonato,
	nomerivista,
)
oppure una cosa tipo
table rivista (
	id,
	...
	nome,
	...
)
table numrivista (
	id,
	idrivista,
	num,
	prezzo,
	...
)
table abbonamento (
	id,
	idabbonato,
	idrivista
)
e tutto il resto uguale.
Problemi/Vantaggi: 
metodo 1: mi trovo centinaia di righe con lo stesso nome e numero diverso.
Quando devo cercare le riviste di un utente (spesso, ma non
tantissimo, diciamo in media una trentina di volte al giorno, di piu` se
metto il tutto consultabile via web come prevedo di fare) devo fare una
ricerca alfabetica invece che numerica su un indice (piu` lenta). Pero`
quando il gestore chiede una lista degli oggetti (molto spesso, qualche
centinaio di volte al giorno, con tendenza verso il migliaio se metto su
web) non devo fare subquery.
metodo 2: se ci sono oggetti non periodici (libri, gadget, ...) non viene
associato nessun numrivista, e se questi raggiungono in numero i periodici
o addirittura li superano (molto probabile, trattandosi di elementi unici)
le ricerche rallentano perche` una join farebbe comunque un prodotto
cartesiano delle due tabelle prima di eliminare quello che non c'entra.
Quindi dovrei complicare il codice per fare le subquery solo quando si
tratta di periodici.
In compenso la struttura del DB e` piu` logica e probabilmente gestibile.
Come DB uso postgres (se puo` servire come indicazione :) e sviluppo il
tutto in python.
C'e` qualcosa che sto trascurando (ottimizzazioni, altre soluzioni, ...)?
Grazie.

Salve, sono un lurker ^_^
Come risposta presento questa analisi, che onestamente richiederebbe un
po' piu' di tempo, saro' stringato ma spero di essere chiaro e
soprattutto di non fare errori. Ricordarsi inoltre che quello che segue
e' strictly IMHO, e che aggiunte.correzioni sono sempre gradite.
Le entita' che identifico nel tuo testo sono Rivista, NumeriRivista e
Abbonato; tra Abbonato e Rivista esiste la relazione (N a N)
Abbonamento, tra Rivista e NumeriRivista la relazione (1 a N) Uscite
(una Rivista puo' avere N Uscite, ma 1 Uscita e' solo di 1 Rivista).  La
vendita riguarda una Copia di una rivista, che puoi considerare un'altra
entita', legata da una relazione 1 a 1 con l'Abbonato (una copia puo'
essere acquistata solo da una persona).
Se vuoi mantenere il tutto denormalizzato ti servono dunque 5 tabelle:
una per ciascuna entita' e una per la relazione N a N Abbonamento, che
richiede spazio a parte.
Da quello che dici non si evince se il prezzo (per il venditore) e il
fornitore delle riviste cambia a seconda dell'uscita, mi sembra di no.
Per le entita' aperiodiche, basta fare in modo di avere 1 record di
uscita per l'entita' (considerando ad es. un libro come una rivista
"degenerata" di cui esce un solo numero).
La struttura sarebbe:
table Riviste (nome, editore, periodicita, costo, prezzo_copertina,
fornitore)
table NumeriRiviste(rivista, data_uscita, numero_rivista, copie_ricevute)
table Abbonati (nome, ...)
table Copie (rivista, numero_rivista, abbonato)
table Abbonamenti (abbonato, rivista, data_inizio, data_fine)
per brevita' non ho indicato gli id. Sono contrario ad usarne di
autogenerati in questo caso. Di solito hanno senso se non ne hai altri a
disposizione, e qui ce ne sono a bizzeffe: per gli abbonati il codice
fiscale, per i fornitori la partita iva...
per i NumeriRiviste userei come PK la combinazione rivista/data_uscita,
perche' alcune riviste usano una numerazione in base all'anno (es. n. 12
del 2004) altre una numeroazione assoluta, cosi' ti "pari" in ambo i casi.
Con questa struttura puoi anche fare altri controlli, es. vedere se hai
venduto piu' copie di quelle che hai ricevuto ((count(*) from Copie
where rivista = nome and data_uscita=data) - copie_ricevute from
NumeriRivista where rivista=nome and data_uscita=data) , o quali
rimanenze ti sono rimaste, il costo totale delle riviste che hai
comprato, ecc.
a parte, se il venditore ha dei fornitori abituali, sarebbe il caso di
fare una tabella Fornitori.
Il resto e' interfaccia. Per gestire libri e gadget, basta inserire una
Rivista di periodicita' nulla e il record corrispondente nella
NumeriRiviste. in pratica:
In questa organizzazione il numero della rivista va ovviamente in
NumeriRiviste, il prezzo di copertina (se non interessa mantenere uno
storico) in Riviste.
HTH >^_^<
Hatanaka


 NumeriRiviste. in pratica:
Il problema mio era principalmente qui, cioe` se demandare all'interfaccia
alcune operazioni oppure farle tutte in SQL.
Per esempio, se arriva Pincopallo in negozio e chiede cosa c'e` di "Pippo"
il gestore fa uan ricerca con Pippo sul nome della rivista, ma potrebbero
esserci anche gadget abbinati, o libri. In questo caso la query sarebbe
qualcosa tipo
select nome from rivista r, numero,prezzo from numerorivista nr where
nr.rivista=
r.id
 and nome like '%Pippo%';
che mi farebbe un prodotto cartesiano delle due tabelle per poi sfoltirlo.
Con 1.000 tra riviste/gadget/libri e magari altrettante uscite mi trovo
una tabella temporanea di 1.000.000 di record su cui fare prima un
confronto id-id e poi una ricerca di tipo text (non indicizzata).
La situazione attuale (con una sola tabella "rivista" senza la
sottotabella "numerorivista", con circa 30.000 righe nella tabella ma la
ricerca in diversi campi) impiega diversi secondi su un K6-400. La
macchina su cui girera` poi sara` un Athlon 1000, ma quello che mi
preoccupa e` che per adesso ci sono solo 2 anni di uscite nel DB, posso
solo immaginare cosa succedera` tra 10 anni... :)
A questo punto sposterei il problema sull'interfaccia: cerco solo in
rivista e poi se clicko su un certo risultato mi interroga numerorivista e
vede cosa e` uscito, ma sarebbe meno immediato per l'utente (il gestore) e
un po' piu` complicato rendere intuitiva l'interfaccia.
Grazie per l'aiuto! :)
Bye.
PS: azzarola, quanto scrivo!