Keine Ahnung, was ich sonst noch tun soll. Ich habe eine Tabelle mit einer Start- und einer Stoppspalte und möchte die Ergebnisse zurückgeben, die sowohl durch Start als auch durch Stopp verbunden sind, und ich möchte eine klare Unterscheidung zwischen den beiden. Jetzt werden beide Abfragen getrennt schnell ausgeführt:
SELECT
UNIX_TIMESTAMP(CONVERT_TZ(start_dev, '+00:00', GetCarrierTimezone(a0.carrier_id))) AS alertStart,
NULL AS alertStop,
c0.name AS carrier_name,
carrier_image,
l0.Latitude,
l0.Longitude
FROM
carriers AS c0
INNER JOIN start_stop AS a0 ON a0.carrier_id = c0.id
INNER JOIN pcoarg AS l0 ON a0.startLogId = l0.id
WHERE
FIND_IN_SET(a0.carrier_id, '89467,1,64578,222625,45013') > 0
AND
start_dev > '2013-03-11 11:46:48'
AND
start_dev = (SELECT MIN(start_dev) FROM start_stop AS a1 WHERE a0.carrier_id = a1.carrier_id AND DATE(a1.start_dev) = DATE(a0.start_dev))
AND IsNotificationInSchedule(22, start_dev) > 0
Also dauert dieser 0,063. Aber wenn ich es in einer UNION kombiniere (egal ob es UNION ALL ODER DISTINCT ODER WAS auch immer ist), dauert es nur ungefähr 0,400 Sekunden.
SELECT * FROM
(
(
SELECT
UNIX_TIMESTAMP(CONVERT_TZ(start_dev, '+00:00', GetCarrierTimezone(a0.carrier_id))) AS alertStart,
NULL AS alertStop,
c0.name AS carrier_name,
carrier_image,
l0.Latitude,
l0.Longitude
FROM
carriers AS c0
INNER JOIN start_stop AS a0 ON a0.carrier_id = c0.id
INNER JOIN pcoarg AS l0 ON a0.startLogId = l0.id
WHERE
FIND_IN_SET(a0.carrier_id, '89467,1,64578,222625,45013') > 0
AND
start_dev > '2013-03-11 11:46:48'
AND
start_dev = (SELECT MIN(start_dev) FROM start_stop AS a1 WHERE a0.carrier_id = a1.carrier_id AND DATE(a1.start_dev) = DATE(a0.start_dev))
AND IsNotificationInSchedule(22, start_dev) > 0
) UNION ALL (
SELECT
NULL AS alertStart,
UNIX_TIMESTAMP(CONVERT_TZ(stop_dev, '+00:00', GetCarrierTimezone(a0.carrier_id))) AS alertStop,
c0.name AS carrier_name,
carrier_image,
l0.Latitude,
l0.Longitude
FROM
start_stop AS a0
INNER JOIN carriers AS c0 ON a0.carrier_id = c0.id
INNER JOIN pcoarg AS l0 ON a0.stopLogId = l0.id
WHERE
FIND_IN_SET(a0.carrier_id, '89467,1,64578,222625,45013') > 0
AND
stop_dev > '2013-03-11 11:46:48'
AND
stop_dev = (SELECT MAX(stop_dev) FROM start_stop AS a1 WHERE a0.carrier_id = a1.carrier_id AND DATE(a1.stop_dev) = DATE(a0.stop_dev))
AND IsNotificationInSchedule(22, start_dev) > 0
)
) AS startStops
ORDER BY IF(alertStart IS NULL, alertStop, alertStart)
Hier ist EXPLAIN für eine einzelne Abfrage:
1 PRIMARY c0 ALL PRIMARY 17 Using where
1 PRIMARY a0 ref PRIMARY,startstop_carriers_stopdev_idx,georefidx,startstop_carriers_startdev_idx startstop_carriers_stopdev_idx 4 test_backoffice.c0.id 72 Using where
1 PRIMARY l0 ref id ASC id ASC 4 test_backoffice.a0.startLogId 1 Using where
2 DEPENDENT SUBQUERY a1 ref PRIMARY,startstop_carriers_stopdev_idx,georefidx,startstop_carriers_startdev_idx startstop_carriers_stopdev_idx 4 test_backoffice.a0.carrier_id 72 Using where; Using index
Und hier ist der EXPLAIN für den JOIN:
1 PRIMARY <derived2> system 0 const row not found
2 DERIVED c0 ALL PRIMARY 17 Using where
2 DERIVED a0 ref PRIMARY,startstop_carriers_stopdev_idx,georefidx,startstop_carriers_startdev_idx startstop_carriers_stopdev_idx 4 test_backoffice.c0.id 72 Using where
2 DERIVED l0 ref id ASC id ASC 4 test_backoffice.a0.startLogId 1 Using where
3 DEPENDENT SUBQUERY a1 ref PRIMARY,startstop_carriers_stopdev_idx,georefidx,startstop_carriers_startdev_idx startstop_carriers_stopdev_idx 4 test_backoffice.a0.carrier_id 72 Using where; Using index
4 UNION c0 ALL PRIMARY 17 Using where
4 UNION a0 ref PRIMARY,startstop_carriers_stopdev_idx,georefidx,startstop_carriers_startdev_idx startstop_carriers_stopdev_idx 4 test_backoffice.c0.id 72 Using where
4 UNION l0 ref id ASC id ASC 4 test_backoffice.a0.stopLogId 1 Using where
5 DEPENDENT SUBQUERY a1 ref PRIMARY,startstop_carriers_stopdev_idx,georefidx,startstop_carriers_startdev_idx startstop_carriers_stopdev_idx 4 test_backoffice.a0.carrier_id 72 Using where; Using index
UNION RESULT <union2,4> ALL
Hilfe in diesem Fall wäre sehr dankbar. :) :)
BEARBEITEN:
Ich bekomme ein inkonsistentes Ergebnis. Wenn ich zum Beispiel convert_tz entferne und versuche, die Zeitzone außerhalb der Union zu ermitteln, erhalte ich sehr schnelle Ergebnisse. Wenn ich das Ergebnis jedoch umbenenne, wird automatisch dieselbe Underperformante-Abfrage ausgeführt:
SELECT
*,
GetCarrierTimezone(carrier_id) timezone
FROM
(
Dies dauert 0,374 s
SELECT
*,
GetCarrierTimezone(carrier_id)
FROM
(
während dies 0,078 dauert (meistens die Verzögerung von der Datenbank zu meiner Maschine) ..
Antworten:
Ich würde erwarten, dass dies aufgrund der BESTELLUNG VON passiert, die Sie dort haben.
Versuchen Sie dies im ersten Teil der UNION:
Und das im zweiten Teil:
Und dann ersetzen Sie die
ORDER BY
durchMit anderen Worten, entfernen Sie die Notwendigkeit für die IF in der Reihenfolge von.
quelle
In einem sehr sehr ähnlichen Fall bemerkte ich aus der Prozessliste von MySQL das sehr schlechte Verhalten von 'In temporäre Tabelle kopieren' (Kopieren von Was? Ich weiß nicht). Ich denke, MySQL hat versucht, einen "besten Ansatz" für die Abfrage zu finden, aber in diesem Fall ist dies fehlgeschlagen. Daher hat die Verwendung von Code zum "Zusammenführen" von 2-Abfrage-Ergebnissen gut funktioniert.
quelle
Der Hauptgrund dafür, dass die Union SQL langsamer läuft, ist, dass eine Union dazu führt, dass mysqld eine interne temporäre Tabelle erstellt. Es wird nur eine Tabelle für eine UNION ALL und eine Tabelle mit einem Index (zum Entfernen von Duplikaten) für eine UNION DISTINCT erstellt.
Hoffe das hilft.
quelle