Ho una tabella MySQL con 100k righe che cattura alcuni log del server creati come:Aggiornamento-join in MySQL estremamente lento rispetto alla query di selezione, senza indici
CREATE TABLE `logs` (
`id` INT NOT NULL AUTO_INCREMENT,
`ip` VARCHAR(16) NULL,
`date` DATETIME NULL,
`session_time` SMALLINT UNSIGNED NULL,
PRIMARY KEY (`id`));
Sto cercando di calcolare il tempo di sessione come il differenza di tempo tra righe consecutive dello stesso IP. Sono in grado di raggiungere questo obiettivo con la seguente query di selezione che richiede meno di un secondo:
SELECT * FROM logs AS a
LEFT JOIN (
SELECT id,
from_unixtime(@diff) AS starttime,
date AS endtime,
IF(@diff = 0, 0, (unix_timestamp(date) - @diff)/60) AS session_time1,
@diff := unix_timestamp(date)
FROM logs,
(SELECT @diff := 0) AS x
ORDER BY ip, logs.date
) AS b ON
a.id = b.id
Tuttavia, quando cerco di usare la query precedente in un update-iscriverti per aggiornare la sessione di tempo, la seguente query di aggiornamento dura più di 600 secondi:
UPDATE logs AS a
LEFT JOIN (
SELECT id,
from_unixtime(@diff) AS starttime,
date AS endtime,
IF(@diff = 0, 0, (unix_timestamp(date) - @diff)/60) AS session_time1,
@diff := unix_timestamp(date)
FROM logs,
(SELECT @diff := 0) AS x
ORDER BY ip, logs.date
) AS b ON
a.id = b.id
SET session_time = session_time1;
Cosa mi manca?
Grazie!
UPDATE: Ecco la EXPLAIN
del select
:
+----+-------------+------------+--------+---------------+------+--------+
| id | select_type | table | type | possible_keys | key | rows |
+----+-------------+------------+--------+---------------+------+--------+
| 1 | PRIMARY | a | ALL | NULL | NULL | 109029 |
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | 108680 |
| 2 | DERIVED | <derived3> | system | NULL | NULL | 1 |
| 2 | DERIVED | logs | ALL | NULL | NULL | 109029 |
| 3 | DERIVED | NULL | NULL | NULL | NULL | NULL |
+----+-------------+------------+--------+---------------+------+--------+
'WHERE ip = '...''? Sembra che tu stia aggiornando tutte le voci 100k ma quelle che stai selezionando ('LEFT JOIN' = elementi che non sono conformi alle regole di selezione nel primo gruppo). Prova a usare "INNER JOIN"? –
Grazie Alejandro, ma non capisco il tuo commento. Perché il inner join dovrebbe essere migliore? Cosa intendi con la clausola 'where'? – kahlo
Scusa, avrei dovuto spiegarlo meglio. Quando usi 'UPDATE', di solito usi una clausola' WHERE' per filtrare quali dati devono essere aggiornati. Nel tuo caso, come vuoi aggiornare per un indirizzo IP specifico, facendo 'WHERE ip = ''' dovrebbe essere meglio per elaborare solo i dati con quell'IP specifico (sto pensando che la tua query stia elaborando ogni record nella tua tabella , anche se non tutti vengono aggiornati). –