Frage

Betrachten Sie die folgende Abfrage:

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

Die Stempel Spalte in den Transaktionen Tabelle ist ein Zeitstempel und gibt es einen Index auf sie. Wie könnte ich diese Abfrage ändern, so dass es vollständigen Tabellenscans vermeidet? (Das heißt, mit Stempel außerhalb der Tag () Funktion)

Danke!

War es hilfreich?

Lösung

Dies ist, wie ich es tun würde:

fügen Sie einige zusätzlichen Felder: Jahr, Monat, Tag oder sogar Stunden, Minuten je nach Verkehr Sie erwarten. Dann baut einen Trigger die zusätzlichen Felder zu füllen, vielleicht das 3-Stunden-Intervall im Voraus abgezogen wird. Schließlich bauen einige Index für die zusätzlichen Felder aus.

Andere Tipps

Wenn das Ziel ist, nur vollständige Tabellenscans zu vermeiden, und Sie haben einen Primärschlüssel (sagen namens PK) für Transaktionen, sollten Sie erwägen, abdeckenden Index

ALTER TABLE Transactions ADD INDEX cover_1 (PK, Stamp)

Dann

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

Diese Abfrage sollte nicht vollständige Tabellenscans verwenden (jedoch kann Optimierer entscheiden Scan zu verwenden, wenn Anzahl der Zeilen in der Tabelle klein ist oder aus irgendeinem anderen statistischen Grund :))

Besserer Weg sein kann, ist temporäre Tabelle zu verwenden, anstatt von Unterabfrage.

Sie können oft die Funktion neu schreiben, so dass Sie etwas haben, das aussieht wie WHERE Stamp=XXXX und XXXX einiger Ausdruck ist. Sie könnten eine Reihe von zwischen den Anweisungen für jeden Monat, WHERE Stamp BETWEEN timestamp('2010-01-01 00:00:00') AND timestamp ('2010-01-01 23:59:59') OR Stamp BETWEEN ... schaffen, aber ich bin nicht sicher, dass dies den Index in diesem Fall verwenden würde. Ich würde eine Spalte erstellen, die den Tag des Monats war wie @petr vermuten lässt.

Berechnen Sie den gewünschten Stempel Wert getrennt, bevor Sie Ihre Haupt-Abfrage ausführen, d.

Schritt 1 - Berechnung der gewünschten Stempelwert

Schritt 2 - eine Abfrage in dem Stempel> (berechneter Wert)

Da es in Schritt 2 keine Berechnung ist sollten Sie in der Lage sein, Ihren Index zu verwenden.

Wenn ich es richtig verstehen, Sie alle Zeilen im Grunde zurückkehren wollen, wo der Stempel in jedem Monat am ersten fällt (mit den 3 Stunden abgezogen wird)? Wenn (und das ist ein großes, wenn ist), Sie haben ein festes Fenster von, sagen die letzten 6 Monate, könnten Sie nur aufzuzählen 6 Bereich Tests. Aber trotzdem, ich bin nicht sicher, indiziert Zugang wird schneller sowieso.

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! Ich bin nicht sicher, wie die Millisekunde Teil des Zeitstempels arbeitet. Sie können es entsprechend Pad benötigen.

Nachbearbeiten petr Antwort ein bisschen die IN-Klausel zu vermeiden, und es für MyISAM oder InnoDB zu machen.

Bei MyISAM

ALTER TABLE Transactions ADD INDEX cover_1 (PK, Stamp)

Oder für InnoDB, wo die PK implizit in jedem Index enthalten ist,

ALTER TABLE Transactions ADD INDEX Stamp (Stamp)

Dann

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

Die Unterabfrage wird einen Index nur Ausführung haben, und die äußere Abfrage nur die Zeilen aus der Tabelle ziehen, wo a.PK kam durch.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top