Domanda

Si consideri la seguente query:

SELECT * FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1;

francobolli colonna Transazioni tavolo è un TIMESTAMP e v'è un indice su di esso. Come potrei cambiare questa query in modo evita scansione completa della tabella? (Vale a dire, usando Timbro al di fuori del al giorno () function)

Grazie!

È stato utile?

Soluzione

Ecco come lo farei:

aggiungere alcuni campi aggiuntivi: anno, mese, giorno o anche ora, minuti a seconda del traffico che ci si aspetta. Poi costruire un trigger per popolare i campi aggiuntivi, forse sottraendo l'intervallo di tre ore in anticipo. Infine costruire qualche indice sui campi aggiuntivi.

Altri suggerimenti

Se l'obiettivo è solo quello di evitare la scansione completa della tabella e si dispone di una chiave primaria (dire il nome PK) per le Operazioni, considerare l'aggiunta di copertura index

ALTER TABLE Transactions ADD INDEX cover_1 (PK, Stamp)

Poi

SELECT * FROM Transactions WHERE PK IN (SELECT PK FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1
 )

Questa query non dovrebbe usare scansione completa della tabella (tuttavia ottimizzatore può decidere di utilizzare la scansione completa, se il numero di righe nella tabella è piccolo o per qualsiasi altro motivo statistico :))

Una migliore modo può essere è quello di utilizzare tabella temporanea invece di subquery.

È spesso può riscrivere la funzione in modo da avere qualcosa che assomiglia WHERE Stamp=XXXX e XXXX è una certa espressione. Si potrebbe creare una serie di tra le dichiarazioni per ogni mese, WHERE Stamp BETWEEN timestamp('2010-01-01 00:00:00') AND timestamp ('2010-01-01 23:59:59') OR Stamp BETWEEN ..., ma io non sono sicuro che questo avrebbe usato l'indice in questo caso. Mi piacerebbe costruire una colonna che era il giorno del mese come @petr suggerisce.

Calcolare il valore del timbro desiderato separatamente prima di eseguire la query principale, cioè.

Fase 1 - Calcolare il valore timbro desiderato

Fase 2 - eseguire una query in cui Stamp> (valore calcolato)

Perché non c'è nessun calcolo al punto 2, si dovrebbe essere in grado di utilizzare l'indice.

Se ho ben capito, che, fondamentalmente, desidera restituire tutte le righe in cui il timbro cade il primo di ogni mese (dopo aver sottratto le 3 ore)? Se (e questo è un grande se), si ha una finestra fissa di, diciamo gli ultimi 6 mesi, si può solo enumerare 6 prove gamma. Ma l'accesso ancora, io non sono sicuro indicizzati sarà più veloce in ogni modo.

select *
  from transactions
 where stamp between timestamp '2010-06-01 03:00:00' and timestamp '2010-06-02 02:59:59'
    or stamp between timestamp '2010-07-01 03:00:00' and timestamp '2010-07-02 02:59:59'
    or stamp between timestamp '2010-08-01 03:00:00' and timestamp '2010-08-02 02:59:59'
    or stamp between timestamp '2010-09-01 03:00:00' and timestamp '2010-09-02 02:59:59'
    or stamp between timestamp '2010-10-01 03:00:00' and timestamp '2010-10-02 02:59:59'
    or stamp between timestamp '2010-11-01 03:00:00' and timestamp '2010-11-02 02:59:59'
    or stamp between timestamp '2010-12-01 03:00:00' and timestamp '2010-12-02 02:59:59';

NB! Io non sono sicuro di come la parte millisecondo del timestamp funziona. Potrebbe essere necessario pad di conseguenza.

Rielaborazione di Petr risposta un po 'per evitare la clausola IN, e di farlo per MyISAM o InnoDB.

Per MyISAM

ALTER TABLE Transactions ADD INDEX cover_1 (PK, Stamp)

In alternativa, per InnoDB, dove il PK è implicitamente incluso in ogni indice,

ALTER TABLE Transactions ADD INDEX Stamp (Stamp)

Poi

SELECT * 
FROM Transactions LEFT JOIN
  (
  SELECT PK 
  FROM Transactions 
  WHERE DAYOFMONTH(Stamp - interval 3 hour) = 1
  ) a ON Transactions.PK=a.PK

La sottoquery avrà un indice solo l'esecuzione, e la query esterna tirerà solo le righe della tabella in cui a.PK venuto attraverso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top