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

.
È stato utile?

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
;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top