MySQL Query puzzle - trovare quella che sarebbe stata la data più recente
Domanda
Ho guardato dappertutto e non hanno ancora trovato un modo intelligente per gestire questo, se mi sento sicuro che uno è possibile:
Una tabella di dati storici ha informazioni trimestrali:
CREATE TABLE Quarterly (
unique_ID INT UNSIGNED NOT NULL,
date_posted DATE NOT NULL,
datasource TINYINT UNSIGNED NOT NULL,
data FLOAT NOT NULL,
PRIMARY KEY (unique_ID));
Un altro tavolo dei dati storici (che è molto grande) contiene informazioni quotidiane:
CREATE TABLE Daily (
unique_ID INT UNSIGNED NOT NULL,
date_posted DATE NOT NULL,
datasource TINYINT UNSIGNED NOT NULL,
data FLOAT NOT NULL,
qtr_ID INT UNSIGNED,
PRIMARY KEY (unique_ID));
Il campo qtr_ID non è parte del feed di dati giornalieri che popolato il database - invece, ho bisogno di compilare retroattivamente il campo qtr_ID nella tabella quotidiana con l'ID fila Quarterly.unique_ID, utilizzando quello che sarebbe stato il più recente dati trimestrali su quel Daily.date_posted per tale origine dati.
Ad esempio, se i dati trimestrali è
101 2009-03-31 1 4.5
102 2009-06-30 1 4.4
103 2009-03-31 2 7.6
104 2009-06-30 2 7.7
105 2009-09-30 1 4.7
ed i dati giornaliera è
1001 2009-07-14 1 3.5 ??
1002 2009-07-15 1 3.4 &&
1003 2009-07-14 2 2.3 ^^
allora vorremmo l'?? campo qtr_ID da assegnare '102' come il recente trimestre più per quella sorgente dati in tale data, e && sarebbe anche '102', e ^^ sarebbe '104'.
Le sfide comprendono che entrambe le tabelle (in particolare la tabella al giorno) sono in realtà molto grandi, non possono essere normalizzati per sbarazzarsi delle date ripetitivi o comunque ottimizzati, e per alcune voci quotidiane non v'è alcuna voce trimestrale precedente.
Ho provato una varietà di join, utilizzando datediff (dove la sfida è trovare il valore minimo di datediff maggiore di zero), e altri tentativi ma niente sta lavorando per me - di solito la mia sintassi è rottura da qualche parte. Tutte le idee sono benvenuti - Io eseguo tutte le idee di base o concetti e di riferire
.Soluzione
Proprio sottoquery per l'id quarto usando qualcosa come:
(
SELECT unique_ID
FROM Quarterly
WHERE
datasource = ?
AND date_posted >= ?
ORDER BY
unique_ID ASC
LIMIT 1
)
Naturalmente, questo probabilmente non vi darà le migliori prestazioni, e si presuppone che le date si aggiungono alla trimestrale sequenziale (altrimenti order by date_posted
). Tuttavia, dovrebbe risolvere il problema.
Si potrebbe utilizzare questo subquery sull'estratto conto INSERT
o UPDATE
come il valore del campo qtr_ID
per la vostra tavola Daily
.
Altri suggerimenti
I seguenti sembra funzionare esattamente come previsto, ma sicuramente è brutto (con tre chiamate alla stessa DATEDIFF !!), forse vedendo una query di lavoro qualcuno potrebbe essere in grado di ridurre ulteriormente o migliorarlo:
UPDATE Daily SET qtr_ID = (select unique_ID from Quarterly
WHERE Quarterly.datasource = Daily.datasource AND
DATEDIFF(Daily.date_posted, Quarterly.date_posted) =
(SELECT MIN(DATEDIFF(Daily.date_posted, Quarterly.date_posted)) from Quarterly
WHERE Quarterly.datasource = Daily.datasource AND
DATEDIFF(Daily.date_posted, Quarterly.date_posted) > 0));
Dopo più di lavoro su questa query, ho finito con enormi miglioramenti delle prestazioni oltre il concetto originale. Il miglioramento più importante è stato quello di creare indici in entrambe le tabelle giornaliere e trimestrali - Daily ho creato gli indici su (origine dati, date_posted) e (date_posted, origine dati) UTILIZZO BTREE e (origine dati) UTILIZZANDO HASH, e nel Quarterly ho fatto lo stesso cosa. Questo è eccessivo ma è fatto in modo che ho avuto la possibilità che il motore di query potrebbe usare. Che ha ridotto il tempo di query a meno dell'1% di quello che era stato. (!!)
Poi, ho imparato che, dato i miei particolari circostanze ho potuto utilizzare MAX () al posto di ORDER BY e LIMIT così io uso una chiamata a MAX () per ottenere l'Unique_ID appropriata. Che ha ridotto il tempo di query di circa il 20%.
Infine, ho imparato che con il motore di memorizzazione InnoDB potevo segmento il pezzo della tabella quotidiana che stavo aggiornando con qualsiasi query, che mi ha permesso di multi-thread le query con un po 'di olio di gomito e di scripting. L'elaborazione parallela funzionava bene e ogni filo ridotto il tempo di risposta lineare.
Quindi, la domanda di base che sta eseguendo letteralmente 1000 volte meglio di quanto il mio primo tentativo è:
UPDATE Daily
SET qtr_ID =
(
SELECT MAX(unique_ID)
FROM Quarterly
WHERE Daily.datasource = Quarterly.datasource AND
Daily.date_posted > Quarterly.dateposted
)
WHERE unique_ID > ScriptVarLowerBound AND
unique_ID <= ScriptVarHigherBound
;