Не знаю, что еще делать с этим. У меня есть одна таблица, в которой есть столбцы start и stop, и я хочу вернуть ее результаты, объединенные как start, так и stop, и я хочу провести четкое различие между ними. Теперь оба запроса выполняются быстро раздельно:
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
Так что этот занимает 0,063. Но если я объединю его в UNION (не имеет значения, является ли он UNION ALL OR DISTINCT OR WHATEVER), это займет около 0,400 секунд.
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)
Вот ОБЪЯСНЕНИЕ по одному запросу:
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
И вот ОБЪЯСНЕНИЕ для СОЕДИНЕНИЯ:
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
Помощь по этому вопросу будет принята с благодарностью. :)
РЕДАКТИРОВАТЬ:
Я получаю противоречивый результат. Если я, например, удаляю convert_tz и пытаюсь получить часовой пояс вне объединения, я получаю очень быстрые результаты, но если я переименую результат, он автоматически переходит к тому же самому низкоэффективному запросу:
SELECT
*,
GetCarrierTimezone(carrier_id) timezone
FROM
(
это занимает 0,374 с
SELECT
*,
GetCarrierTimezone(carrier_id)
FROM
(
в то время как это занимает 0,078 (в основном, отставание от БД до моей машины) ..
Ответы:
Я ожидаю, что это произойдет из-за того, что у вас там ЗАКАЗ.
Попробуйте это в первой части UNION:
И это во второй части:
А потом заменить
ORDER BY
сДругими словами, удалите необходимость IF в порядке по.
источник
В очень похожем случае я заметил из списка процессов mysql очень плохое поведение «копировать в временную таблицу» (копирование «Что? Я не знаю»). Я думаю, что mysql соблазнил «лучший подход» для запросов, но в этом случае не получилось, поэтому использование кода для «слияния» результатов двух запросов работало нормально.
источник
Основная причина медленного выполнения объединения sql заключается в том, что объединение заставляет mysqld создать внутреннюю временную таблицу. Он создает только таблицу для UNION ALL и таблицу с индексом (для удаления дубликатов) для UNION DISTINCT.
Надеюсь это поможет.
источник