On Thu, 19 Nov 2020 17:53:20 +0100, cb <
c...@ppt.io.it> wrote:
>Ho una select che mi ritorna una grossa mole di dati
>SELECT column1,column2 FROM table ORDER BY column1 LIMIT $count OFFSET
>$offset;
>Senza il LIMIT viene cancellata per time limit exceeded e piacevolezze
>del genere
>L'utente poi puo' cambiare il LIMIT ed il COUNT.
>Ma sono costretto a ri-sottometere la query che a causa dell' ORDER BY
>mi scorre tutto il DB.
La cosa si può fare, ma non in modo pulito.
Il fatto è che il resultset ottenuto dalla tua query va perduto non appena la
pagina ha terminato di caricarsi; quindi, appena vedi le prime 50 righe, ecco
che le righe da 51 a 200000 non esistono più.
C'è un sistema molto brutto che consente di fare funzionare la cosa usando un
processo worker, AJAX e un CURSOR lato MySQL. Però è complicato, difficile da
gestire, e i cursori di MySQL sono asensitivi e monotoni: questa seconda cosa
significa che se vai da pagina 1 a pagina 2 tutto bene - ma indietro non puoi
tornare.
Quindi l'alternativa dolorosa è stivare i dati in un'area temporanea, per poi
accedere a quella.
I sistemi sono due. Fanno schifo entrambi.
Col primo sistema crei una tabella di appoggio con la tua query... ma siccome
ti servirà di paginarla, ti serve un numero di riga perché, altrimenti, torni
a dover usare OFFSET e LIMIT e fai la fine di Raniere.
Quindi la tua
SELECT col1, col2
deve diventare ben tre query:
SET @recno = 0;
CREATE TABLE temp_018374 AS
SELECT col1, col2, @recno:=@recno+1 AS recno FROM (segue il resto
della query con ORDER ma senza LIMIT);
ALTER TABLE temp_018374 ADD recno PRIMARY KEY;
La tua paginazione poi si traduce in
SELECT * FROM temp_018374
WHERE recno BETWEEN {$pagestart} AND {$pageend}
ORDER BY recno;
e poi devi trovare il modo di fare un DROP TABLE temp_018374 a fine cose. Ti
può servire il comando "SHOW TABLES LIKE 'temp_%';".
Sono possibili variazioni e ottimizzazioni che però dipendono dalla query da
paginare (hint: puoi mettere in temp* le primary key che ti servono, fare la
paginazione da temp* e poi giocare di SELECT...WHERE primarykey IN (...) per
arricchire la pagina di righe. E' un casino fare 50 query? Sì. Ma sono tutte
query su primary key, ci sta che tu ci riesca agile.
Il secondo sistema è peggio ancora e prevede di prelevare tutte le righe, il
che richiede un processo secondario con set_time_limit(0) forkato, farci già
tutto il necessario per formattare i dati, e archiviare il risultato o in un
terrificante archivio di pagine (quindi, /tmp/paging/query1235/1/120.json ti
contiene la pagina 120, per dire) o in un terrificante database SQLite. Pure
lì ti tocca poi pulire.
Se no, sapendo esattamente com'è fatta la tabella e quante righe ha, e quali
query ci fai girare sopra (c'è una WHERE? Fatta come?), si può vedere se c'è
modo di fare qualcosa di meglio.
Oppure, in circostanze sufficientemente sfigate questo ti aiuterebbe assa':
OPTIMIZE TABLE `table`;
o all'estremo:
CREATE TABLE ciccio LIKE `table`;
INSERT INTO ciccio SELECT * FROM `table` ORDER BY column1;
ALTER TABLE `table` RENAME TO `table_old`;
ALTER TABLE `ciccio` RENAME to `table`;
-- see what I did there?
O magari è possibile sfruttare il partitioning, che ne so io?
Leonardo
--
"You all presumably know why" :-) :-(