Dunno, co dalšího s tímhle dělat. Mám jednu tabulku, která má sloupce start a stop a chci vrátit výsledky z ní spojené jak startem, tak stopem a chci mezi nimi jasně rozlišit. Nyní oba dotazy běží rychle odděleně:
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
Tohle trvá 0,063. Ale pokud to zkombinuji v unii (nezáleží na tom, jestli je to UNION ALL OR DISTINCT OR WHATEVER)), trvá to jen asi 0,400 sekundy.
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)
Zde je EXPLAIN na jeden dotaz:
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
A tady je VYSVĚTLENÍ ZA PŘIPOJENÍ:
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
Pomoc v tomto by byla velmi oceněna. :)
ÚPRAVA:
Mám nekonzistentní výsledek. Pokud například odeberu convert_tz a pokusím se dostat časové pásmo mimo unii, dostanu velmi rychlé výsledky, ale pokud přejmenuji výsledek, automaticky přejde na stejný nevyhovující dotaz:
SELECT
*,
GetCarrierTimezone(carrier_id) timezone
FROM
(
to trvá 0,374 s
SELECT
*,
GetCarrierTimezone(carrier_id)
FROM
(
zatímco to trvá 0,078 (většinou zpoždění z db na můj stroj) ..
Očekával bych, že se to stane, protože tam máte OBJEDNÁVKU.
Vyzkoušejte to v první části unie:
SELECT
UNIX_TIMESTAMP(CONVERT_TZ(start_dev, '+00:00', GetCarrierTimezone(a0.carrier_id))) AS alertFoo,
/* NULL AS alertStop, */
A to ve druhé části:
SELECT
/* NULL AS alertStart, */
UNIX_TIMESTAMP(CONVERT_TZ(stop_dev, '+00:00', GetCarrierTimezone(a0.carrier_id))) AS alertFoo,
A pak ORDER BY
Nahraďte
ORDER BY alertFoo
Jinými slovy, odstraňte potřebu IF v pořadí podle.
Ve velmi podobném případě jsem si všiml ze seznamu procesů mysql velmi špatné chování 'copy to temp table' (kopírování Co? Nevím). Myslím, že mysql v pokušení 'nejlepší přístup' pro dotazování, ale v tomto případě selhal, takže použití kódu 'sloučit' 2-výsledky dotazu fungovalo dobře.
Hlavním důvodem pomalejšího běhu unie sql je to, že spojení způsobí, že mysqld vytvoří interní dočasnou tabulku. Vytvoří pouze tabulku pro UNION ALL a tabulku s indexem (odstranění duplikátů) pro UNION DISTINCT.
Snad to pomůže.