Je ne sais pas quoi faire d'autre à propos de celui-ci. J'ai une table qui a des colonnes start et stop et je veux en renvoyer les résultats joints à la fois par start et par stop et je veux une distinction claire entre les deux. Maintenant, les deux requêtes s'exécutent rapidement séparément:
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
Donc, celui-ci prend 0,063. Mais si je le combine en UNION (peu importe que ce soit UNION ALL OU DISTINCT OU QUELQUE CHOSE), cela ne prend que 0,400 secondes.
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)
Voici EXPLAIN sur une seule requête:
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
Et voici l'EXPLIQUER pour le 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
De l'aide sur celui-ci serait grandement appréciée. :)
ÉDITER:
J'obtiens un résultat incohérent. Si je supprime le convert_tz par exemple et essaie d'obtenir le fuseau horaire en dehors de l'union, j'obtiens des résultats très rapides, mais si je renomme le résultat, il revient automatiquement à la même requête underperformante:
SELECT
*,
GetCarrierTimezone(carrier_id) timezone
FROM
(
cela prend 0,374 s
SELECT
*,
GetCarrierTimezone(carrier_id)
FROM
(
alors que cela prend 0,078 (principalement le décalage de la base de données vers ma machine) ..
Réponses:
Je m'attendrais à ce que cela se produise en raison de la COMMANDE PAR que vous avez là-dedans.
Essayez ceci dans la première partie de l'UNION:
Et ceci dans la deuxième partie:
Et puis remplacez le
ORDER BY
parEn d'autres termes, supprimez le besoin du CI dans l'ordre de.
la source
Dans un cas très très similaire, j'ai remarqué à partir de la liste des processus de mysql le très mauvais comportement de «copier dans la table temporaire» (copier quoi? Je ne sais pas). Je pense que mysql a tenté une «meilleure approche» pour les requêtes, mais dans ce cas, a échoué, donc utiliser du code pour «fusionner» les résultats de 2 requêtes a bien fonctionné.
la source
La raison principale du ralentissement de l'union sql est qu'une union fait que mysqld crée une table temporaire interne. Il crée juste une table pour UNION ALL et une table avec un index (pour supprimer les doublons) pour UNION DISTINCT.
J'espère que cela t'aides.
la source