ho una tabella di database che rappresenta una gerarchia di file e directory, con la seguente struttura (semplificato):approccio efficiente per l'aggiornamento di massa di una tabella gerarchica
ItemId int Path text Type int (0 for files, 1 for directories) ParentId int BackupTime datetime
Attualmente la colonna BackupTime
viene utilizzato solo per i file , è impostato su null per le directory.
Ora devo compilare questa colonna anche per le directory: deve essere il minimo BackupTime
di tutti i discendenti (file e directory).
Questo (ingenuo e inefficiente) domanda illustra quello che voglio fare:
update Items i
set BackupTime = (select min(BackupTime)
from Items d
where d.Path like i.Path || '%'
and d.Type = 0)
where i.Type = 1
Il mio problema è che io non riesco a trovare un approccio efficiente. La query sopra prende troppo a lungo su grandi volumi di dati (questa tabella contiene spesso più di 100K righe)
Probabilmente sarebbe più veloce per cercare le min(BackupTime)
solo sui figli diretti:
update Items i
set BackupTime = (select min(BackupTime)
from Items d
where d.ParentId = i.ItemId)
where i.Type = 1
Ma per questo per funzionare, devo assicurarmi che i discendenti vengano aggiornati prima dei loro antenati, quindi devo percorrere la gerarchia in modo ricorsivo dal basso verso l'alto. Il problema è che non ho un modo semplice per sapere quali oggetti sono i più profondi nella gerarchia. Sto usando SQLite, quindi non posso usare le query gerarchiche.
Qualche idea su come farlo in modo efficiente?
Idealmente, preferirei essere in grado di farlo in una singola query UPDATE, ma se non è possibile io sono aperto ad altre opzioni, purché siano efficienti
Grazie, ci provo! –
OK, ci sono voluti 5 secondi per elaborare un DB con 100000 elementi ... è abbastanza buono;).Ho provato con un database "fittizio", quindi è necessario verificarne uno reale, ma sono certo che avrà prestazioni simili. BTW, l'ultima condizione con 'not exists' non è necessaria: se c'è un null,' min' restituirà null, quindi alla fine darà lo stesso risultato, con meno iterazioni (14 invece di 27 nel mio test) –
MIN restituirà NULL se i valori * only * sono NULL. MIN NON restituirà NULL se NULL e altri valori sono aggregati. NON ESISTE è necessario per garantire che le iterazioni vadano dal basso verso l'alto. Se rimuovi il NON ESISTE, ottieni risultati sbagliati! Supponiamo che/dir1/contenga due elementi: 1) un file con BackupTime 4/12 e 2) una directory/dir2/che contenga 1 file con tempo di backup 4/9. Senza NOT EXISTS,/dir1/otterrà un BackupTime non corretto di 4/12 durante la prima iterazione. Con NOT EXISTS, aspetterà fino alla prossima iterazione. Le poche iterazioni che vedi suggeriscono queste risposte sbagliate. –