2016-04-29 6 views
8

Ich verwende derzeit die folgende Abfrage, die ca. 8 Minuten dauert, um das Ergebnis aufgrund der Datenmenge zurückgeben (ca. 14 Monate). Kann ich das bitte beschleunigen?SQL - beschleunigen Sie die Abfrage

Die betreffende Datenbank ist MySQL mit InnoDB-Engine

select 
    CUSTOMER as CUST, 
    SUM(IF(PAGE_TYPE = 'C',PAGE_TYPE_COUNT,0)) AS TOTAL_C, 
    SUM(IF(PAGE_TYPE = 'D',PAGE_TYPE_COUNT,0)) AS TOTAL_D 
from 
     PAGE_HITS 
where 
    EVE_DATE >= '2016-01-01' and EVE_DATE <= '2016-01-05' 
    and SITE = 'P' 
    and SITE_SERV like 'serv1X%' 
group by 
    CUST 

Daten von 6 Monaten verteilt. Jede Spalte, die in die WHERE-Klausel eingeht, wird indiziert. Dort wäre eine ganze Reihe von Indizes & eine große Liste hier aufzulisten. Daher nur in Worten zusammenfassen. Im Hinblick auf diese Abfrage ist EVE_DATE + PAGE_TYPE_COUNT eines des zusammengesetzten Indizes & so CUST + SITE_SERV + EVE_DATE sind, EVE_DATE + SITE_SERV, EVE_DATE + SITE,

Der Primärschlüssel ist eigentlich eine dummy Autoinkrement Nummer. Es wird nicht verwendet, um ehrlich zu sein. Ich habe keinen Zugriff auf den EXPLAIN-Plan. Ich werde sehen, was ich dafür tun kann.

Ich würde mich über jede Hilfe freuen, diese bitte zu verbessern.

+5

Können Sie angeben, welche Indizes verwendet werden (falls vorhanden) und wie die Strukturen aussehen? Primärschlüssel werden verwendet usw.? – CR41G14

+2

könnten Sie mehr Details zur Verfügung stellen: Anzahl Zeilen, Indizes, Speicher-Engine und usw. –

+0

Vielen Dank. Leider habe ich die Aktualisierung dieser Details verpasst. Lass mich das jetzt tun. – usert4jju7

Antwort

2

Okay, ganz gut, wie die Partitionstabelle Bereich auf EVE_DATE ist, welche Partition zu lesen das DBMS leicht sehen soll. Es geht also darum, welchen Index man dann verwenden soll.

Es gibt eine Spalte, die Sie auf Gleichheit prüfen (SITE = 'P'). Dies sollte in Ihrem Index an erster Stelle stehen. Sie können dann EVE_DATE und SITE_SERV in beliebiger Reihenfolge hinzufügen. Daher sollte Ihr Index in der Lage sein, die fraglichen Tabellendatensätze so schnell wie möglich zu finden.

Wenn Sie jedoch die anderen Felder in der Abfrage zu Ihrem Index verwendet hinzufügen, würde die Tabelle nicht einmal gelesen werden müssen, weil alle Daten im Index avaliable wäre selbst:

create index on page_hits(site, eve_date, site_serv, customer, page_type, page_type_count); 

Dies sollte der optimale Index für Ihre Abfrage sein, wenn ich mich nicht irre.

+0

Vielen Dank, Thorsten. Dies verbesserte die Leistung um ein gewisses Maß. – usert4jju7

2

Der wichtigste Optimierungsfaktor wären Indizes. Man sollte Ihre Anfrage so genau wie möglich, zum Beispiel entspricht:

EVE_DATE, SITE, CUST, SITE_SERV 

Die Reihenfolge ist wichtig, zumindest für SITE_SERV als letzten Wert; Wenn Sie LIKE verwenden, verwenden Sie nicht den vollen Wert, was die Indexeffizienz für die nächsten Spalten verschlechtert.

Sie können auch ein kleines bisschen gewinnen, indem Sie die IF entfernen und Typ und Anzahl zurückgeben; vielleicht können Sie diesen Wert in Ihrer Front-Anwendung bearbeiten/formatieren?

Wie auch immer, Sie sollten mit der Profilerstellung Ihrer aktuellen Abfrage beginnen, indem Sie EXPLAIN verwenden, um zu sehen, was schief läuft. Wenn das nicht möglich ist, könnten Sie versuchen, Struktur, Indizes und ein paar Dummy-Daten in einer lokalen DB zu reproduzieren, Volume ist dort irrelevant.

+0

Danke Preuk. Ich bin glücklich, 'IF' zu entfernen, wie könnte ich die bedingte' SUM' auf effiziente Weise berechnen? Könntest du bitte hier helfen? – usert4jju7

+0

Ich würde sagen, wählen Sie einfach 'PAGE_TYPE, SUM (PAGE_TYPE_COUNT) AS TOTAL' und verwalten Sie den 'C' oder 'D' Fall in Ihrer Frontend-Anwendung; aber wie ich schon sagte ist es wahrscheinlich nicht mal das wert. Einige Tippfehler korrigiert, mein Satz hat keinen Sinn ergeben – Preuk

+0

Danke Preuk. Ich werde diesen Vorschlag anderswo in meiner Entwicklung verwenden. In Bezug auf diese Frage bin ich in der Lage, Daten in jedem DB-Layer zu verarbeiten :( – usert4jju7

3

Ich habe die Daten nicht, so dass ich die Geschwindigkeit nicht testen kann, aber ich denke, es wäre schneller.

select 
    CUSTOMER as CUST, 
    SUM(PAGE_TYPE_COUNT * (PAGE_TYPE = 'C')) AS TOTAL_C, 
    SUM(PAGE_TYPE_COUNT * (PAGE_TYPE = 'D')) AS TOTAL_D 
from 
     PAGE_HITS 
where 
    EVE_DATE >= '2016-01-01' and EVE_DATE <= '2016-01-05' 
    and SITE = 'P' 
    and SITE_SERV like 'serv1X%' 
group by 
    CUST 

Es funktionierte auf meiner Geige auf MySql 5.6

+0

Netter Trick, ich werde das definitiv versuchen, um einige Abfragen zu vereinfachen, die ich habe; Leistungsmäßig, haben Sie zufällig eine Metrik? – Preuk

+0

Danke Xpy. Das sieht großartig aus. Ich werde das sicherlich woanders verwenden. In meinem Fall gibt es keine Perf Verbesserung. Das ist ein wirklich guter aber – usert4jju7

2

Fügen Sie diese beiden Indizes:

INDEX(site, date) 
INDEX(site, site_serv) 

Der Optimierer auf die Statistik schauen und zwischen ihnen wählen. Grob gesagt wäre die erste besser, wenn es weniger Zeilen mit 'P' & DATEN in diesem Bereich gibt, als 'P' & 'serv1X%'.

Ja, der "deckende" Index, dass Thorsten vielleicht besser ist, aber er hat mehr Felder, als ich gerne in einen Index setze.

PARTITIONingkönnte helfen. Aber es gibt zu wenig Informationen, um es sicher zu sagen. Der Grund für die Partitionierung könnte sein, dass Sie eine "2-dimensionale" Suche haben - einen Datumsbereich und 'serv1X%'. Sie müssten entweder nach Datum oder site_serv partitionieren und dann die PRIMARY KEY(site, ..., ...) mit der anderen von (date oder site_serv) als zweite Spalte haben. Der Rest der Spalten müsste sowohl den Partitionsschlüssel als auch einige Spalten enthalten, um sie eindeutig zu machen. Das wird so unordentlich, dass ich nicht darüber nachdenken möchte.

+0

Danke Rick. Dies half bei der Verbesserung der Leistung. – usert4jju7