UNION lambat tetapi kedua kueri cepat terpisah

11

Tak tahu harus bagaimana lagi dengan yang ini. Saya punya satu tabel yang memiliki awal dan berhenti kolom dan saya ingin mengembalikan hasilnya bergabung dengan mulai dan dengan berhenti dan saya ingin perbedaan yang jelas antara keduanya. Sekarang kedua query berjalan dengan cepat:

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

Jadi yang ini membutuhkan 0,063. Tetapi jika saya menggabungkannya dalam UNION (tidak masalah apakah itu UNION ALL ATAU DISTINCT ATAU APA PUN) itu hanya membutuhkan sekitar 0,400 detik.

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)

Berikut adalah MENJELASKAN pada permintaan tunggal:

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

Dan di sini adalah MENJELASKAN untuk BERGABUNG:

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                     

Bantuan yang satu ini akan sangat dihargai. :)

EDIT:

Saya mendapatkan hasil yang tidak konsisten. Jika saya menghapus convert_tz misalnya dan mencoba untuk mendapatkan zona waktu di luar serikat saya mendapatkan hasil yang sangat cepat, tetapi jika saya mengubah nama hasilnya secara otomatis turun ke permintaan yang kurang kinerja yang sama:

SELECT
    *,
    GetCarrierTimezone(carrier_id) timezone
FROM
(

ini membutuhkan 0,374s

SELECT
    *,
    GetCarrierTimezone(carrier_id)
FROM
(

sementara ini membutuhkan 0,078 (kebanyakan lag dari db ke mesin saya) ..

helderjsm
sumber
Yang paling sederhana adalah dengan menjalankannya secara terpisah dan menggabungkan hasilnya dalam aplikasi.
ypercubeᵀᴹ
hai @ ypercube, itu terlintas di benak saya :) tetapi sangat jelek untuk melakukan itu dan mempertahankan kode itu. Selain itu saya masih harus mengurutkan hasilnya di php.
helderjsm
Maksud saya menjalankan 2 pertanyaan dengan jenis yang diinginkan. Maka Anda hanya perlu bergabung dalam php (no sorting).
ypercubeᵀᴹ
1
Penyortiran tidak linier. Hasil kueri 1 dapat di antara hasil kueri 2.
helderjsm
1
Saya tidak berpikir @ ypercube mengasumsikan hasilnya tidak tumpang tindih: 'penggabungan' jauh lebih murah / lebih mudah daripada jenis yang diterapkan di php. Tentu saja memperbaiki masalah dalam SQL jika memungkinkan akan menjadi solusi yang jauh lebih baik :)
Jack mengatakan coba topanswers.xyz

Jawaban:

1

Saya berharap ini terjadi karena ORDER OLEH Anda miliki di sana.

Coba ini di bagian pertama UNION:

SELECT
            UNIX_TIMESTAMP(CONVERT_TZ(start_dev, '+00:00', GetCarrierTimezone(a0.carrier_id))) AS alertFoo,
            /* NULL AS alertStop, */

Dan ini di bagian kedua:

SELECT
            /* NULL AS alertStart, */
            UNIX_TIMESTAMP(CONVERT_TZ(stop_dev, '+00:00', GetCarrierTimezone(a0.carrier_id))) AS alertFoo,

Dan kemudian ganti ORDER BYdengan

ORDER BY alertFoo

Dengan kata lain, hapus kebutuhan untuk IF dalam urutan oleh.

Thomas Kejser
sumber
Hai Thomas, Pertama-tama terima kasih atas ulanganmu. Seperti yang saya katakan di posting sebelumnya ini sudah diperbaiki beberapa waktu yang lalu. Masalahnya adalah saya perlu membedakan antara tanda 1 dan tanda 2. Dalam kasus apa pun urutan dilakukan pada hasil gabungan dan bukan pada gabungan itu sendiri. Tidak ada banyak hasil untuk membenarkan lambatnya permintaan.
helderjsm
0

Dalam kasus yang sangat mirip, saya perhatikan dari daftar proses mysql perilaku yang sangat buruk dari 'copy to temp table' (menyalin Apa? Saya tidak tahu). Saya pikir mysql tergoda 'pendekatan terbaik' untuk query, tetapi dalam kasus ini gagal, jadi menggunakan kode untuk 'menggabungkan' hasil 2-query bekerja dengan baik.

realtebo
sumber
Hai realtebo, Terima kasih atas masukannya. Ini agak lama sekarang, tetapi untuk apa yang saya ingat ketidakkonsistenan adalah karena beberapa cara mysql adalah caching beberapa hasil dan bukan yang lain. Saya akhirnya menciptakan kembali query dengan cara yang lebih efisien khususnya dengan melacak nilai-nilai yang saya butuhkan dalam tabel terpisah sehingga indeks lebih efisien.
helderjsm
0

Alasan utama untuk menjalankan sql union lebih lambat adalah bahwa union menyebabkan mysqld untuk membuat tabel sementara internal. Ini hanya membuat tabel untuk UNION ALL dan tabel dengan indeks (untuk menghapus duplikat) untuk UNION DISTINCT.

Semoga ini membantu.

hai semuanya
sumber