2016-06-09 6 views
4

Ich habe eine MySQL-Datenbank mit InnoDB Tabellen zusammenfassend über 10 zehn GB Daten, die ich von MySQL 5.5 auf MySQL 5.7 migrieren möchte. Und ich habe eine Abfrage, die ein bisschen wie folgt aussieht:Abfrage extrem langsam nach der Migration auf MySQL 5.7

SELECT dates.date, count(mySub2.myColumn1), sum(mySub2.myColumn2) 
FROM (
    SELECT date 
    FROM dates -- just a table containing all possible dates next 5 years 
    WHERE date BETWEEN '2016-06-01' AND '2016-09-03' 
) AS dates 
LEFT JOIN (
    SELECT o.id, time_start, time_end 
    FROM order AS o 
    INNER JOIN order_items AS oi on oi.order_id = o.id 
    WHERE time_start BETWEEN '2016-06-01' AND '2016-09-03' 
) AS mySub1 ON dates.date >= mySub1.time_start AND dates.date < mySub1.time_end 
LEFT JOIN (
    SELECT o.id, time_start, time_end 
    FROM order AS o 
    INNER JOIN order_items AS oi on oi.order_id = o.id 
    WHERE o.shop_id = 50 AND time_start BETWEEN '2016-06-01' AND '2016-09-03' 
) AS mySub2 ON dates.date >= mySub2.time_start AND dates.date < mySub2.time_end 
GROUP BY dates.date; 

Mein Problem ist, dass diese Abfrage ausführt schnell in MySQL 5.5, aber extrem langsam in MySQL 5.7.

In MySQL 5.5 dauert es mehr als 1 Sekunde und < 0,001 Sekunden jede wiederkehrende Ausführung ohne Neustart von MySQL.
In MySQL 5.7 dauert es mehr als 11,5 Sekunden und 1,4 Sekunden bei jeder wiederkehrenden Ausführung, ohne MySQL neu zu starten.
Und je mehr LINKE JOINs ich der Abfrage hinzufügen, desto langsamer wird die Abfrage in MySQL 5.7.

Beide Instanzen laufen jetzt auf demselben Computer, auf derselben Festplatte und mit denselben my.ini-Einstellungen. Es ist also keine Hardware.
Die Ausführungspläne unterscheiden sich jedoch, und ich weiß nicht, was ich daraus machen soll.

Dies ist die 5,5 VERLÄNGERT auf MySQL EXPLAIN:

| id | select_type | table  | type | possible_keys | key   | key_len | ref  | rows | filtered | extra       | 
|----|-------------|------------|-------|---------------|-------------|---------|-----------|-------|----------|---------------------------------| 
| 1 | PRIMARY  | dates  | ALL |    |    |   |   | 95 | 100.00 | Using temporary; Using filesort | 
| 1 | PRIMARY  | <derived2> | ALL |    |    |   |   | 281 | 100.00 | ''        | 
| 1 | PRIMARY  | <derived3> | ALL |    |    |   |   | 100 | 100.00 | ''        | 
| 3 | DERIVED  | o   | ref | xxxxxx  | shop_id_fk | 4  | ''  | 1736 | 100.00 | ''        | 
| 3 | DERIVED  | oc   | ref | xxxxx   | order_id_fk | 4  | myDb.o.id | 1  | 100.00 | Using index      | 
| 2 | DERIVED  | o   | range | xxxx   | date_start | 3  |   | 17938 | 100.00 | Using where      | 
| 2 | DERIVED  | oc   | ref | xxx   | order_id_fk | 4  | myDb.o.id | 1  | 100.00 | Using where      | 

Dies ist die auf MySQL 5.7 ausgefahren ist Explain:

| id | select_type | table | type | possible_keys | key   | key_len | ref    | rows | filtered | extra   | 
|----|-------------|-------|--------|---------------|-------------|---------|------------------|------|----------|----------------| 
| 1 | SIMPLE  | dates | ALL |    |    |   |     | 95 | 100.00 | Using filesort | 
| 1 | SIMPLE  | oi | ref | xxxxxx  | order_id_fk | 4  | const   | 228 | 100.00 |    | 
| 1 | SIMPLE  | o  | eq_ref | xxxxx   | PRIMARY  | 4  | myDb.oi.order_id | 1 | 100.00 | Using where | 
| 1 | SIMPLE  | o  | ref | xxxx   | shop_id_fk | 4  | const   | 65 | 100.00 | Using where | 
| 1 | SIMPLE  | oi | ref | xxx   | order_id_fk | 4  | myDb.o.id  | 1 | 100.00 | Using where | 

ich verstehen will, warum die MySQLs die gleiche Abfrage behandeln, die viel anders und wie kann ich MySQL 5.7 optimieren, um schneller zu sein?
Ich bin nicht auf der Suche nach Hilfe beim Neuschreiben der Abfrage, um schneller zu sein, da das ist etwas, das ich bereits alleine mache.

+0

Nur um sicher zu gehen ... (1) die Abfragen sind genau die gleichen? (2) die Tabellen, einschließlich der Indizes, sind genau gleich? – Uueerdo

+0

@Uueerdo ja, genau. Zuerst war es auf verschiedenen Maschinen. Aber als ich das entdeckte, installierte ich sowohl MySQL 5.5 als auch MySQL 5.7 auf meinem Laptop und importierte den gleichen Dump zweimal. Und ich nahm die gleiche my.ini und machte ein Minimum an Änderungen, damit ich die beiden Instanzen auf einmal ausführen konnte. Also ist alles gleich. Und nur dann habe ich dieselbe Abfrage auf sie ausgeführt. –

+0

Ich habe dann keine Ahnung. Meine Vermutung wäre, dass Optimierungen für häufigere Arten von Abfragen vorgenommen würden, die sich negativ auf diese spezielle (und seltsame) Abfrage auswirken würden. – Uueerdo

Antwort

6

Wie in den Kommentaren zu lesen ist, hat @wchiquito vorgeschlagen, sich die optimizer_switch anzusehen. Hier habe ich festgestellt, dass der Schalter derived_merge ausgeschaltet werden konnte, um dieses neue und in diesem speziellen Fall unerwünschte Verhalten zu beheben.

set session optimizer_switch='derived_merge=off'; behebt das Problem.

+0

Sie können ein wenig mehr in dem folgenden Artikel lesen: [abgeleitete Tabellen in MySQL 5.7] (http://mysqlserverteam.com/derived-tables-in-mysql-5-7/) und [9.2.1.18 Unterabfrage Optimierung] (https://dev.mysql.com/doc/refman/5.7/de/subquery-optimization.html#derived-table-optimization). – wchiquito

+0

Vielen Dank. Ich habe die gleiche Situation und Ihre Lösung funktioniert. In meinem Fall gibt mysql-5.5 das Ergebnis nach 0.5s und mysql-5.7 zurück - nach 1.2s. Nach dem Deaktivieren von abgeleiteten_Merge-Optimierer und Neuschreiben der Abfrage von Joins zu Unterabfragen mysql-5.7 gibt das Ergebnis nach 0.01s –

+0

Danke @ nl-x. Habe einen ganzen Tag damit verbracht, herauszufinden, warum eine Abfrage, die 0,9 Sekunden auf dem alten MySQL-Datenbankserver dauerte, 4,5 Minuten auf dem MariaDB-Server dauerte. Durch das Deaktivieren des Flags 'derived_merge' wurde die Zeit für die Abfrage MariaDB auf 0,8 Sekunden verringert. Was für ein Unterschied! Ich verstehe nicht, warum dieses Flag auf ON gesetzt ist, wenn der Performance-Hit so groß ist. Oder zumindest sollte MariaDB es besser für Benutzer, die von MySQL wechseln, dokumentieren. – Johnny

1

Aufbau und die Pflege einer „Übersichtstabelle“ würde diese Abfrage laufen viel schneller als noch 1 Sekunde (Dies kann auch mit set global ... oder werden gesetzt in der my.cnf/my.ini erfolgen). Eine solche Tabelle würde wahrscheinlich shop_id, date und einige zählen.

More on summary tables.

Verwandte Themen