2017-12-08 1 views
0

Erzwingen Ich versuche, eine Abfrage zu optimieren, aber erklären Abfrage gibt, dass mysql keinen Index verwendet.Nicht in der Lage, Index auf Mysql-Index

Dies ist meine Frage:

explain 
SELECT t1.* 

    FROM crypto_screener.prices as t1 FORCE INDEX (PRIMARY) 

    where t1.id = (
     select t2.id 
     from (select * 
       from 
       crypto_screener.prices FORCE INDEX (allfilters) 
       where date > '2017-12-07' 
      ) as t2 
     where t2.symbol = t1.symbol 
     order by t2.id desc 
     limit 1 
    ) 
; 

Dies ist show index from prices;

Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment 
prices 0 PRIMARY 1 id A 57718 NULL NULL  BTREE  
prices 0 priceid 1 id A 57718 NULL NULL  BTREE  
prices 1 pricefilters 1 symbol A 369 NULL NULL YES BTREE  
prices 1 pricefilters 2 date A 57718 NULL NULL YES BTREE  
prices 1 datefilters 1 date A 506 NULL NULL YES BTREE  
prices 1 symbolfilters 1 symbol A 421 NULL NULL YES BTREE  
prices 1 allfilters 1 id A 57718 NULL NULL  BTREE  
prices 1 allfilters 2 symbol A 57718 NULL NULL YES BTREE  
prices 1 allfilters 3 date A 57718 NULL NULL YES BTREE  

Die Abfrage in der Tabelle nicht jetzt mit der Datenmenge ausgeführt werden. Wie kann ich das optimieren?

+0

Sie können 'allfilters' hier nicht verwenden (da es ein Index über 3 Spalten und Datum ist nicht die erste Spalte im Index, also im Grunde ist dieser Index nutzlos, da Sie bereits einen Index über die ID haben) Können Sie verwenden 'Datumsfilter'? –

+0

@RolandStarke Ja, Datefilters funktioniert auf t2 –

+1

Großartig. Reicht es, um die Leistung zu steigern? Ich kann mir nicht vorstellen, was diese Abfrage auswählt. Es wäre interessant zu wissen. –

Antwort

1

Es sieht so aus, als ob Sie die Zeile mit dem höchsten id Wert für jeden einzelnen symbol Wert innerhalb des bestimmten Datumsbereichs wünschen.

Hier ist, wie Sie das tun. Verwenden Sie zuerst eine Unterabfrage, um eine Liste der Werte symbol, id zu erhalten, die den höchsten Wert id für jedes Symbol für die Teilmenge Ihrer Tabelle mit den gewünschten Daten enthält.

    SELECT symbol, MAX(id) id 
        FROM prices 
        WHERE date > '2017-12-07' 
        GROUP BY symbol 

Diese Unterabfrage kann auf date, symbol, id durch eine Verbindung Index optimiert werden. Warum? Es greift nach dem Zufallsprinzip auf den Index zu dem ersten wählbaren Datum zu und durchsucht es dann sequentiell nach verschiedenen Werten von Symbol und ID.

Sie können diese Unterabfrage testen. Stellen Sie sicher, dass es Ihnen vernünftige Ergebnisse liefert.

verwenden sie dann in einer Hauptabfrage, etwa so:

SELECT t1.* 
    FROM prices t1 
    JOIN (
       SELECT symbol, MAX(id) id 
        FROM prices 
        WHERE date > '2017-12-07' 
        GROUP BY symbol 
     ) t2 ON t1.id = t2.id AND t1.symbol = t2.symbol 

Jetzt, da Ihre id Werte alle einzigartig sind, können Sie durch Weglassen AND t1.symbol = t2.symbol die ON Zustand vereinfachen.

Dies sollte, mit dem richtigen zusammengesetzten Index, in der Tat sehr schnell laufen.

Pro-Tipp 1: Erstellen Sie keine zusätzlichen Indizes nur für ein gutes Maß. Stellen Sie sicher, dass sie vorhanden sind, um eine Abfrage zu unterstützen, die Sie ausführen müssen.

Pro-Tipp 2: date > '2017-12-07' schließt Zeilen um Mitternacht an dem von Ihnen angegebenen Datum aus, nimmt aber alle Zeilen nach Mitternacht an diesem Datum. Wenn der Datentyp Ihrer date Spalte DATETIME ist, ist die Verwendung von > wahrscheinlich falsch. Wenn der Datentyp DATE ist, bedeutet Ihr Filter dasselbe wie date >= '2017-12-08'.

Pro-Tipp 3: Der Versuch, den MySQL-Abfrageplaner zur Verwendung bestimmter Indizes zu zwingen, ist normalerweise kontraproduktiv. Viel besser ist sicherzustellen, dass Sie die richtigen Indizes haben.

+0

Danke für diese Antwort. Ich habe eine Weile mit diesem Problem gekämpft. Sehr beeindruckende und elegante Lösung. Herzlichen Glückwunsch, ich bin beeindruckt. –