Newsgroup: it.comp.www.php
Titolo: mysql timeout e query

$sql="SELECT * FROM piatti, ingredienti, ricette WHERE ";
$sql.="((ingredienti.ingrediente LIKE '%$stringa%' AND 
ingredienti.IDingrediente = ricette.IDingrediente AND piatti.IDpiatto = 
ricette.IDpiatto) OR (piatti.nomepiatto LIKE '%$stringa%')) ORDER BY 
piatti.nomepiatto";
C'è un errore di concetto in questa query? mysql mi va in timeout dopo 30 
secondi.... se tolgo la parte relativa all'OR funziona perfettamente. 

Cekko ha scritto:

Errore di concetto: utilizza le join, invece dei prodotti cartesiani.
Già così risparmi un bel po' di tempo e ne guadagni in leggibilità.
poi la OR a cosa serve?
a quanto vedo prendi 3 tabelle, metti in relazione ingredieni e ricette 
per mezzo di IDingrediente, e piatti e ricette per mezzo di IDpiatto
Se i 2 like servono per filtrare, la query dovrebbe essere così
select * from (piatti p join ricette r using (IDpiatto)) join 
ingredienti i using (IDingrediente) where i.ingrediente like 
'%$stringa%' or p.nomepiatto like '%$stringa%'
Il tuo problema è che mettendo le condizioni di join come filtro su un 
prodotto cartesiano, o metti le parentesi e raggruppi bene le operazioni 
logiche, oppure utilizzi le join e nel where metti solamente le 
condizioni di filtro.
PS:
se piatti, ingredienti e ricette fossero tabelle con 100 righe l'una, 
con la tua query prima generi una tabella grande 100^3 righe (1 milione 
di righe) alla quale applichi 2 filtri semplici e 2 filtri con la 
maschera (che quindi controllano tutta la stringa)
Aumenta a 200 elementi l'una e fai un po' i calcoli di quanto cresce.
Utilizzando le join (se hai definito delle chiavi primarie, cosa che mi 
auguro) il dbms fa prima una hashjoin (in pratica va a prendere 
direttamente i record che gli interessano in modo molto più veloce, 
log(n) invece che n) e i filtri vengono applicati solo ai record 
effettivamente risultanti (che sono decisamente meno)
LP

La tua query funziona e forse un giorno ne comprenderò il significato, ma mi 
restituisce più valori identici anche se metto "select distinct.... come 
mai? 

 ha scritto nel messaggio 
news:epgm3p$qej$1...@nnrp.ngi.it...


 Mi spieghi quel log(n) invece di n*n*n....?
Si tratta della complessità dell'algoritmo.
É un po' lunga da spiegare, in termini rigorosi.
Tagliato su questo caso, immagina di avere un array.
Devi ricercare un elemento.
Se l'array fosse di 300 elementi, nel caso peggiore devi scorrere 300 
elementi prima di trovare (o non trovare) l'elemento che ti interessa
Complessità n
Se l'array fosse un array a 2 dimensioni da 300 elementi per 500 
elementi, scorrendola tutta passi per 300x500=150000 elementi
Complessità n*n
Se l'array fosse un array a 3 dimensioni da 300 elementi per 500 per 
250, stavolta dovresti ricercare in 37500000 elementi
Complessità n*n*n
Esistono delle strutture dati che ti permettono, invece, di ricercare un 
elemento utilizzando un numero decisamente inferiore di controlli.
Senza scendere nei particolari, per trovare un elemento tra 37500000, è 
possibile fare solamente 23 controlli (decisamente meno).
La definizione di chiavi primarie nelle tabelle e la creazione di 
opportuni indici, permette al dbms di crearsi appunto queste strutture 
dati e fare ricerche tra milioni di dati con pochi controlli (ergo in 
poco tempo). La non definizione degli stessi, porta ovviamente alla 
scansione di _tutti_ gli elementi.
Utilizzando, come facevi tu, un prodotto cartesiano tra le tabelle, 
mysql si trova in una condizione a dir poco scomoda.
Infatti facendo una query del tipo
select * from a,b where 
a.id
=
b.id
;
prende ciascun elemento di a e lo mette in relazione con ciascun 
elemento di b, successivamente filtra tutti i record dove 
a.id
=
b.id
.
Per due tabelle piccole, non è un problema. Per 3 tabelle la cosa 
diventa: ciascun elemento di a in relazione con ciascun elemento di b, e 
ciascuna relazione trovata tra a e b, con ciascun elemento di c.
Reitera per 4,5,6 tabelle, e il problema ti esplode in mano.
L'utilizzo delle join, invece, è decisamente più efficente
select * from a join b using (id) where <vattelapesca>
oppure
select * from a join b on (
a.id
=
b.id
) where <vattelapesca>
prende ciascun elemento di a, cerca in b gli elementi che soddisfano la 
regola di join (ossia 
a.id
=
b.id
, le due diciture sono equivalenti, ma la 
prima può essere utilizzata solamente se le colonne indicate appaiono 
con lo stesso nome in entrambe le tabelle) e, per ciascun record che 
soddisfa la regola dell'unione, esegue i test <vattelapesca>
Già così scremi in modo notevole.
Nel caso che id non fosse chiave primaria di b, il sistema si fa ancora 
una volta una scansione di tutti gli elementi di b per cercare quello/i 
che soddisfano la regola.
Nel caso, invece, che id fosse chiave primaria, o che fosse definito un 
indice, mysql opererebbe con una ricerca più efficente e quindi impiega 
molto meno tempo.
Tutto questo è spiegato in termini semplici e non rigorosi.
Se vuoi saperne di più, ti consiglio di prenderti uno o più libri 
sull'argomento e studiare un po'. L'argomento è comunque molto ampio.
[...]
Luca

 piatto/ingrediente associato a 2 o più id differenti
No, questo lo escludo.....

Dovresti fare il prof... tutto chiarissimo ora. Grazie della tua pazienza.

 Devi verificare lo schema.
no, semplicemente distinct * non e' una sintassi valida

>no, semplicemente distinct * non e' una sintassi valida
ok grazie.
Domanda come faccio a definire una coppia di chiavi come primaria? si può o 
non è necessario?