Consigli su come tagliare questo codice

di il
21 risposte

Consigli su come tagliare questo codice

Un consiglio su come rendere più veloci queste istruzioni con dei select più complessi?


if(isset($_GET["check_upload"])){
	$elenco = array();
	$CATEGORIA = "Fumetti";
	$DATA = "2020-01-02";
	if(mysqli_num_rows($result = mysqli_query($mysqli_connection, "SELECT * FROM foto WHERE categoria = '$CATEGORIA' AND cartella_locale = '$DATA' AND link IS NOT NULL GROUP BY gruppo ORDER BY percorso ASC"))>0){
		while($riga = mysqli_fetch_assoc($result)){
			if(mysqli_num_rows($result1 = mysqli_query($mysqli_connection, "SELECT link FROM foto WHERE categoria = '$CATEGORIA' AND cartella_locale = '$DATA' AND gruppo = '{$riga['gruppo']}' AND link IS NOT NULL"))==mysqli_num_rows($result2 = mysqli_query($mysqli_connection, "SELECT * FROM foto WHERE categoria = '$CATEGORIA' AND cartella_locale = '$DATA' AND gruppo = '{$riga['gruppo']}'"))){
				//TUTTE LE RIGHE DEL GRUPPO HANNO IL LINK
				$elenco[] = $riga["gruppo"]; 
			}else{
				$n = mysqli_num_rows($result_diff = mysqli_query($mysqli_connection, "SELECT * FROM foto WHERE categoria = '$CATEGORIA' AND cartella_locale = '$DATA' AND gruppo = '{$riga['gruppo']}' AND link IS NULL ORDER BY percorso ASC"));
				while($riga_diff = mysqli_fetch_assoc($result_diff)){
					$elenco[] = $riga["gruppo"]."_".$riga_diff["nome_foto"]; 
				}
			}
		}
	}

21 Risposte

  • Re: Consigli su come tagliare questo codice

    melixo ha scritto:


    Un consiglio su come rendere più veloci queste istruzioni con dei select più complessi?
    Hai solo un modo...
    Cancellare sto mappazzone di codice, studiare e ricominciare.
    In caso di errore ripetere l'operazione.
  • Re: Consigli su come tagliare questo codice

    melixo ha scritto:


    Un consiglio su come rendere più veloci queste istruzioni con dei select più complessi?
    Studia come selezionare record mettendo in correlazione le tabelle tramite i SQL Joins.

    Invece di recuperare un set di record e, ciclando, recuperare i record correlati, metti quindi in "join" tra loro le tabelle coinvolte che contengono i dati da recuperare indicando quali sono i legami che correlano appunto i record tra loro (es. campi chiave) così da recuperarli in un sol colpo e lasciando al DB il compito di ottimizzare le ricerche e la preparazione del cosiddetto "resultset".

    Ciao!
  • Re: Consigli su come tagliare questo codice

    Eh non mi riesce, la tabella è una sola, ci sono quasi tutta la notte leggendo tra select, count, distinct, group, having ecc
    l'ho migliorata usando i count ma è comunque sempre un mostro di codice, perché io divido per gruppi e poi per ogni gruppo faccio un select, ma così oltre che essere sì facile, è anche un mostro, perché i gruppi potrebbero arrivare ad essere anche centinaia, e fare centinaia di query non la finisce più, considerando che fa tutto parte di un setInterval da 15 secondi...

    perché io ho ad esempio 1.000 righe
    c'è la colonna gruppo, e le righe sono divise in gruppi.
    colonna gruppo - colonna link
    1 - http...
    1 - http...
    1 - Error...
    2 - http...
    2 - http...
    3 - http...
    3 - http...
    e così via

    Quindi ci sono i gruppi in cui tutte le righe hanno un link valido (WHERE link LIKE 'http@')
    E gruppi che potrebbero avere sia un link valido che degli Error
    tutti gli altri possono essere solamente tutti NULL, ma quello l'ho risolta all'inizio mettendo WHERE link IS NOT NULL.

    E quindi dovrei fare delle query tipo
    SELECT * FROM tabella WHERE link LIKE 'http@' AND (il numero di righe del gruppo è uguale al numero di righe con WHERE link LIKE 'http@' ) il tutto diviso per gruppi GROUP BY gruppo
    Il fatto è che se io lo divido per gruppi poi la query mi restituisce 1, 2, 3, 4, 5 ecc mentre io ho bisogno però di recuperare il link di ogni riga divise per gruppi

    perché diversamente (ELSE)
    -> il gruppo ha delle righe con http e delle righe con degli Error
    (Seleziona tutti i gruppi che hanno sia link LIKE 'Error@' che link LIKE 'http@')

    praticamente devo uscirne con 2 array. Il primo con la lista di tutti i gruppi che hanno tutti i link, e il secondo con la lista di tutti i gruppi che hanno dei link ma ci sono stati degli errori

    In poche parole una cosa del genere
    "SELECT * FROM foto WHERE link IS NOT NULL AND ((COUNT OF link OF gruppo = COUNT OF link WHERE link LIKE 'http@') GROUP BY gruppo)"
  • Re: Consigli su come tagliare questo codice

    Potresti iniziare a valutare se conviene dividere i dati in piu' tabelle, questo ti aiuterebbe sia nell'indicizzare i dati (quindi maggiore velocità di esecuzione se mi parli di migliaia di records) sia nella ricerca con le join sql.

    se descrivi come è struttura la tabella possiamo fare della valutazioni piu' precise, a parte la colonna gruppi non hai specificato altro.
  • Re: Consigli su come tagliare questo codice

    La tabella ha solamente 3 colonne
    gruppo, nome_foto, link

    1 riga per ogni foto
    le foto appartengono a diversi gruppi, 10 foto potrebbero appartenere al primo gruppo, 15 al secondo gruppo ecc ecc
    ogni foto ha un link (http... ecc) oppure se il link è mancante ci deve essere un "Error"
    solo che io faccio prima un GROUP BY gruppo, e ottengo una riga per gruppo. Poi per ogni gruppo faccio un SELECT e controllo se tutti hanno "http" nel link, oppure un "Error"
    Così ottengo una lista di tutti quelli completi, e una lista di tutti quelli incompleti...

    Applausi... il problema è che è troppo pesante. Se trova centinaia di gruppi addio... in più è un'operazione che deve eseguire ogni 15 secondi... diventa pesantissimo fatto come l'ho fatto io.

    Leggendomi tutte le funzioni sql, tra count, having ecc ecc non riesco a trovare la quadra per creare una query unica che eviti di fare un ciclo su ogni singolo gruppo

    1 - http...
    1 - http...
    1 - Error...
    2 - http...
    2 - http...
    3 - http...
    3 - http...
    e così via

    praticamente un array deve contenere 3 elementi (perché il gruppo 1 non è completa) e un altro array deve avere 4 elementi perché 2 gruppi da 2 sono completi...
    però questa cosa degli array ci riesco.
    Ciò che non riesco a scrivere una query complessa

    una cosa del genere

    lista_completi = SELECT * FROM foto WHERE (il numero di righe di un gruppo è uguale al numero di righe, all'interno dello stesso gruppo, che hanno nella colonna link LIKE "http%")
    lista_non_completi = SELECT * FROM foto WHERE (all'interno di uno stesso gruppo, ci sono sia http che Error)
  • Re: Consigli su come tagliare questo codice

    Il group concat potrebbe essere una soluzione ma dispendiosa perchè di fatto potresti concatenare o 1 o xxxx records (dovresti poi modificare il group_concat_max_len altrimenti ti taglia la stringa), inoltre non capisco perchè devi fare due select per avere i link buoni da quelli errati basta un ifnull sul campo link, se è vuoto imposti tu la stringa "Error@".

    Io farei fare tutto al buon php con un ciclo di array.
    
    	// raccogli TUTTI i records, imposterei manualmente il campo "errore_foto" giusto per ciclare piu' facilmente i records dopo
    	$sql = mysqli_query($mysqli_connection, "select gruppo, nome_foto, ifnull(link,'Error@') as link, if(link IS NOT NULL,0,1) as errore_foto from FOTO where......");
    	$records = mysqli_fetch_assoc($sql);
    	
    	// poi fai un ciclo per dividere i link buoni da quelli errati
    	// dichiari il nuovo array
    	$arrayFoto = [];
    	foreach($records as $r){
    		if($r['errore_foto'] == 1){
    			//se la foto è in errore popoliamo l'array foto errate
    			$arrayFoto['errate'][] = $r;
    			// oppure metti tu i dati che vuoi
    			$arrayFoto['errate'][] = $r['gruppo']."_".$r['nome_foto']."_",$r['link'];
    		}else{
    			//altrimenti popoliamo l'array delle foto buone
    			$arrayFoto['buone'][] = $r;
    			// oppure metti tu i dati che vuoi
    			$arrayFoto['errate'][] = $r['gruppo']."_".$r['nome_foto']."_",$r['link'];
    		}
    	}
    
    	
    Cosi facendo abbiamo creato un array multidimensionale con al proprio interno due subarray di foto..quelle buone e quelle errate..
    se fai un print_r($arrayFoto) vedrai il risultato.

    Adesso potrai gestire singolarmente i due array creati.

    Con 8 righe di codice hai finito


    EDIT: Collegando il post nella board JS sul JSON parse stampando un json_encode($arrayFoto) e facendo il parse in JS avrai esattamente gli stessi 2 array foto buone ed errate.
  • Re: Consigli su come tagliare questo codice

    melixo ha scritto:


    praticamente un array deve contenere 3 elementi (perché il gruppo 1 non è completa) e un altro array deve avere 4 elementi perché 2 gruppi da 2 sono completi...
    però questa cosa degli array ci riesco.
    Ciò che non riesco a scrivere una query complessa

    una cosa del genere

    lista_completi = SELECT * FROM foto WHERE (il numero di righe di un gruppo è uguale al numero di righe, all'interno dello stesso gruppo, che hanno nella colonna link LIKE "http%")
    lista_non_completi = SELECT * FROM foto WHERE (all'interno di uno stesso gruppo, ci sono sia http che Error)
    Questo l'hai aggiunto dopo al post, non lo avevo letto.
    Ti modifico il codice, basta modificare l'array principale
    
    
    	// raccogli TUTTI i records, imposterei manualmente il campo "errore_foto" giusto per ciclare piu' facilmente i records dopo
    	$sql = mysqli_query($mysqli_connection, "select gruppo, nome_foto, ifnull(link,'Error@') as link, if(link IS NOT NULL,0,1) as errore_foto from FOTO where......");
    	$records = mysqli_fetch_assoc($sql);
    	
    	// poi fai un ciclo per dividere i gruppi completi da incompleti
    	// dichiari il nuovo array
    	$arrayFoto = [];
    	foreach($records as $r){
    		if($r['errore_foto'] == 1){
    			//se la foto è in errore popoliamo l'array gruppo incompleti
    			$arrayFoto['incompleti'][$r['gruppo'][] = $r;
    			// oppure metti tu i dati che vuoi
    			$arrayFoto['incompleti'][$r['gruppo'][] = $r['gruppo']."_".$r['nome_foto']."_",$r['link'];
    		}else{
    			//altrimenti popoliamo l'arrayi gruppi completi
    			$arrayFoto['completi'][$r['gruppo'][] = $r;
    			// oppure metti tu i dati che vuoi
    			$arrayFoto['completi'][$r['gruppo'][] = $r['gruppo']."_".$r['nome_foto']."_",$r['link'];
    		}
    	}
    
    
    adesso hai 2 array dentro $arrayFoto..$arrayFoto['completi'] e $arrayFoto['incompleti']..dentro ognuno di loro hai i gruppi divisi.
  • Re: Consigli su come tagliare questo codice

    Ti ringrazio per l'interesse, adesso guarderò bene cosa mi hai risposto perché ad una prima occhiata non ho capito alcune cose.
    questo if nella query me la guardo bene...
    Poi ti risponderò meglio.

    Ad una prima occhiata posso dirti che anche io avevo pensato di prendere direttamente tutti i record e fare un while.
    Il problema è che se da una parte fare un select per ogni gruppo, considerando che potevano essere anche centinaia e doverlo fare ogni 15 secondi, un while su ogni riga potrebbero essere migliaia e migliaia di righe, perchè ogni gruppo può contenere anche 15, 20 righe... e non volevo appensantire comunque.
    Mi chiedevo quindi se esisteva una query complessa e annidata che evitasse cicli di select o di while
  • Re: Consigli su come tagliare questo codice

    melixo ha scritto:


    Mi chiedevo quindi se esisteva una query complessa e annidata che evitasse cicli di select o di while
    Ma se interessi una tabella sola che query complessa vuoi utilizzare? Devi comunque ciclare i dati ottenuti.
  • Re: Consigli su come tagliare questo codice

    Sì, è vero, lo stavo per scrivere che un ciclo lo devo fare comunque
    però al di là che if e ifnull adesso me li leggo bene come funzionano, credo proprio che sia molto più veloce fare come dici tu.
    Ti ringrazio

    praticamente si creano 2 set di risultati, uno chiamato link e uno chiamato errore_foto (sono dati da quel "as"), giusto?
    ifnull(link,'Error@')
    questo significa che se il campo link è NULL allora
    if($r['link'] = Error@

    mentre questo
    if(link IS NOT NULL,0,1)
    significa che se il campo link NON è NULL allora imposta a 0, diversamente lo imposta a 1
    ??
  • Re: Consigli su come tagliare questo codice

    Esatto, se il campo link è null allora il campo link stesso sarà 'Error@' altrimenti il link.
    stessa cosa per l'if..se il campo non è null allora l'errore sarà 0 altrimenti 1
  • Re: Consigli su come tagliare questo codice

    C'è solo un appunto che vorrei fare...
    1) Queste operazioni verranno richiamate ogni 15 secondi (e sin qui non centra nulla)
    2) Possiamo escludere tutti i campi NULL, perché i campi NULL ci sarebbero solamente perché su quel gruppo non è stata fatta ancora nessuna operazione, quindi si potrebbe scremare ancora di più.
    Un campo NULL non è un Error, è solo perché in quel gruppo non è stata fatta nessuna operazione
    nel senso che potranno esserci solamente queste combinazione
    gruppo link
    1 http
    1 http
    1 http

    2 NULL
    2 NULL
    2 NULL
    2 NULL

    3 http
    3 http
    3 Error

    4 Error
    4 Error
    4 Error
    4 Error

    ma mai

    5 NULL
    5 http
    5 http
    oppure
    6 Error
    6 http
    6 NULL

    In poche parole o saranno tutti null i link di un gruppo, oppure tutti http, o tutti Error o Error e http insieme
    Se una riga di un gruppo è NULL anche tutti gli altri lo sono

    è per questo io agli inizi degli inizi avevo messo
    
    	if(mysqli_num_rows($result = mysqli_query($mysqli_connection, "SELECT * FROM foto WHERE link IS NOT NULL GROUP BY gruppo ORDER BY percorso ASC"))>0){
    
  • Re: Consigli su come tagliare questo codice

    In modo tale che le operazioni che hai scritto farle solamente sui campi NOT NULL
    praticamente questi
    ifnull(link,'Error@') as link, if(link IS NOT NULL,0,1)
    vedo un po' di sostituirli con i LIKE
    perché in fin dei conti con LIKE devo solo cercare gli http, o gli Error, per fare i 2 array
    solo che facendo così mi trova anche i gruppi dove http ed Error, convivono
  • Re: Consigli su come tagliare questo codice

    Se il valore link NON sarà MAI null allora puoi fare la query cosi
    select gruppo, nome_foto, if(link LIKE 'Error%',1,0) as errore_foto from FOTO where ...... and link is not null

    in questo modo escludi i risultati con link NULL che per definizione esclude di fatto tutto il gruppo
Devi accedere o registrarti per scrivere nel forum
21 risposte