2016-10-14 4 views
1

Sorry, ich könnte nicht genauer im Titel sein.Optimierung der Indizes für lange MySql Abfrage

Also habe ich diese Anfrage:

CREATE TABLE RecordPoints AS (
SELECT competitionId, personId, personCountryId, eventId, year, date, 
if(regionalAverageRecord = 'WR', 
(SELECT COUNT(DISTINCT personId) FROM ResultDates rd 
WHERE rd.eventId=rd2.eventId AND rd.date <= rd2.date AND rd.average > 0), 0) wrAveragePoints, 
if(regionalSingleRecord = 'WR', 
(SELECT COUNT(DISTINCT personId) FROM ResultDates rd 
WHERE rd.eventId=rd2.eventId AND rd.date <= rd2.date), 0) wrSinglePoints, 
if(NOT regionalAverageRecord in('WR', 'NR'), 
(SELECT COUNT(DISTINCT personId) FROM ResultDates rd 
WHERE rd.eventId=rd2.eventId AND rd.date <= rd2.date AND average > 0 AND rd.personCountryId in 
(SELECT Countries.id FROM Countries JOIN Continents on Countries.continentId=Continents.id where recordName = rd2.regionalAverageRecord)), 0) crAveragePoints, 
if(NOT regionalAverageRecord in('WR', 'NR'), 
(SELECT COUNT(DISTINCT personId) FROM ResultDates rd 
WHERE rd.eventId=rd2.eventId AND rd.date <= rd2.date AND rd.personCountryId in 
(SELECT Countries.id FROM Countries JOIN Continents on Countries.continentId=Continents.id where recordName = rd2.regionalSingleRecord)), 0) crSinglePoints, 
if(regionalAverageRecord = 'NR', 
(SELECT COUNT(DISTINCT personId) FROM ResultDates rd 
WHERE rd.eventId=rd2.eventId AND rd.date <= rd2.date AND rd.personCountryId=rd2.personCountryId AND rd.average > 0), 0) nrAveragePoints, 
if(regionalSingleRecord = 'NR', 
(SELECT COUNT(DISTINCT personId) FROM ResultDates rd 
WHERE rd.eventId=rd2.eventId AND rd.date <= rd2.date AND rd.personCountryId=rd2.personCountryId), 0) nrSinglePoints 
FROM ResultDates rd2 WHERE (NOT regionalAverageRecord='' OR NOT regionalSingleRecord = '')); 

Und es dauerte 9 Stunden zu beenden. Um es aufzuschlüsseln, erstelle ich eine Tabelle, in der 6 der Spalten ganze Unterabfragen sind, um zu zählen, wie oft eine PersonId in der gleichen Tabelle erscheint, bevor das erste, was ich mir ansehe, basierend auf dem Datum und ein paar passiert ist andere Spalten. Erstellen Sie einen Index auf das Datum mit CREATE INDEX date ON ResultDates (date) beschleunigte es ein wenig ich denke, aber es dauert immer noch eine monsterhafte Menge an Zeit.

Die Zeilen in ResultDates aussehen wie

+------------+-----------------+---------------+---------+---------+-----+---------+----------------------+-----------------------+-------+-----+------+------------+ 
| personId | personCountryId | competitionId | eventId | roundId | pos | average | regionalSingleRecord | regionalAverageRecord | month | day | year | date  | 
+------------+-----------------+---------------+---------+---------+-----+---------+----------------------+-----------------------+-------+-----+------+------------+ 
| 1982THAI01 | USA    | WC1982  | 333  | f  | 1 |  0 | WR     |      |  6 | 5 | 1982 | 1982-06-05 | 
+------------+-----------------+---------------+---------+---------+-----+---------+----------------------+-----------------------+-------+-----+------+------------+ 

Wo regionalSingleRecord und regionalAverageRecord können jede dieser "RecordNames" sein: WR, NR, nichts die meiste Zeit oder AfR, ASR, ER, NAR, OCR- oder SAR, die ich dann zum Nachschlagen einer countryId verwende, basierend auf welchem ​​Kontinent diese recordNames verbunden sind.

Ich habe Indizes erstellt, um diese RecordNames mit Kontinenten und Kontinent-IDs mit CountryIds zu verbinden, nicht sicher, wie sehr dies jedoch die Geschwindigkeit verbesserte.

drauf ERKLÄREN Lauf gibt mir dies:

+----+--------------------+------------+------------+------+-------------------+--------------+---------+----------------------------------+--------+----------+---------------------------------------------------------------+ 
| id | select_type  | table  | partitions | type | possible_keys  | key   | key_len | ref        | rows | filtered | Extra               | 
+----+--------------------+------------+------------+------+-------------------+--------------+---------+----------------------------------+--------+----------+---------------------------------------------------------------+ 
| 1 | PRIMARY   | rd2  | NULL  | ref | idx_personId  | idx_personId | 32  | const       | 567 | 99.00 | Using where             | 
| 9 | DEPENDENT SUBQUERY | rd   | NULL  | ALL | date,idx_personId | NULL   | NULL | NULL        | 992294 |  0.33 | Range checked for each record (index map: 0x3)    | 
| 8 | DEPENDENT SUBQUERY | rd   | NULL  | ALL | date,idx_personId | NULL   | NULL | NULL        | 992294 |  0.11 | Range checked for each record (index map: 0x3)    | 
| 6 | DEPENDENT SUBQUERY | Continents | NULL  | ref | P_id,recordIndex | recordIndex | 9  | cubing.rd2.regionalSingleRecord |  1 | 100.00 | Using index; Start temporary         | 
| 6 | DEPENDENT SUBQUERY | Countries | NULL  | ALL | NULL    | NULL   | NULL | NULL        | 203 | 10.00 | Using where; Using join buffer (Block Nested Loop)   | 
| 6 | DEPENDENT SUBQUERY | rd   | NULL  | ALL | date    | NULL   | NULL | NULL        | 992294 |  0.33 | Range checked for each record (index map: 0x1); End temporary | 
| 4 | DEPENDENT SUBQUERY | Continents | NULL  | ref | P_id,recordIndex | recordIndex | 9  | cubing.rd2.regionalAverageRecord |  1 | 100.00 | Using index; Start temporary         | 
| 4 | DEPENDENT SUBQUERY | Countries | NULL  | ALL | NULL    | NULL   | NULL | NULL        | 203 | 10.00 | Using where; Using join buffer (Block Nested Loop)   | 
| 4 | DEPENDENT SUBQUERY | rd   | NULL  | ALL | date    | NULL   | NULL | NULL        | 992294 |  0.11 | Range checked for each record (index map: 0x1); End temporary | 
| 3 | DEPENDENT SUBQUERY | rd   | NULL  | ALL | date,idx_personId | NULL   | NULL | NULL        | 992294 |  3.33 | Range checked for each record (index map: 0x3)    | 
| 2 | DEPENDENT SUBQUERY | rd   | NULL  | ALL | date,idx_personId | NULL   | NULL | NULL        | 992294 |  1.11 | Range checked for each record (index map: 0x3)    | 
+----+--------------------+------------+------------+------+-------------------+--------------+---------+----------------------------------+--------+----------+---------------------------------------------------------------+ 

Ich habe einige googeln zu tun, wie die Geschwindigkeit zu verbessern. Aufgrund meines Googelns weiß ich, dass es nicht gut aussieht. Vor allem mit den 992294 Zeilen, die ich in meiner anfänglichen Tabelle sehe.

Mein Problem ist jedoch, dass ich nicht weiß, wie man alles optimiert, um alles schneller zu machen. Ich habe gelesen, dass sorgfältig erstellte Indizes die Geschwindigkeit erheblich verbessern können, also bin ich gespannt, welche Art von Indizes hier verwendet werden kann.

Antwort

0

Unterabfragen in Auswahlsätzen können sehr kostspielig sein. Korrelierte Unterabfragen sind im Allgemeinen schlechte Performer und haben in der Regel bessere Alternativen.

Ich habe keine Zeit, um eine gründliche Antwort zu geben, aber mein allgemeiner Eindruck vom Skimming der Abfrage ist, dass Sie wahrscheinlich es zu JOIN ResultDates umwandeln können, einmal in der Hauptabfrage; und dann bedingte Aggregation in der SELECT-Klausel verwenden. So etwas wie dies ...

SELECT rd.competitionId, rd.personId, rd.personCountryId, rd.eventId 
    , rd.year, rd.date 
    , COUNT(DISTINCT IF(rd.regionalAverageRecord = 'WR' AND rdPrev.average > 0, rdPrev.person_id, NULL) AS wrAveragePoints 
    , COUNT(DISTINCT IF(regionalSingleRecord = 'WR', rdPrev.person_id, NULL) AS wrSinglePoints 
    , [etc....] 
FROM ResultDates AS rd 
LEFT JOIN ResultDates AS rdPrev 
    ON rd.eventId=rdPrev.eventId 
    AND rdPrev.date <= rd.date 
WHERE (NOT rd.regionalAverageRecord='' OR NOT rd.regionalSingleRecord = '') 
; 

Edit: Für die Unterabfragen/Felder die Countries und Continents Tabellen beteiligt, können Sie in der Lage sein, nur LEFT JOIN zu diesen Tabellen als auch verwenden, um die verbundenen Werte in einer Weise ähnlich wie Ich habe gezeigt, rdPrev.average in der wrAveragePoints Berechnung verwendet wird.

Hinweis: COUNT() und die meisten anderen Aggregationsfunktionen ignorieren NULL-Werte.