BİRLİĞİ yavaş ama her iki sorgu da ayrı ayrı hızlı


11

Bu konuda başka ne yapacağını bilmiyorum. Ben bir başlangıç ​​ve bir durdurma sütunları olan bir tablo var ve ben hem başlangıç ​​hem de durdurma tarafından birleştirilen sonuçlarını döndürmek istiyorum ve ikisi arasında net bir ayrım istiyorum. Şimdi her iki sorgu da ayrı ayrı hızlı çalışıyor:

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

Yani bu 0.063 alır. Ama eğer bunu bir sendikada birleştirirsem (BİRLİKTE VEYA ÇEŞİTLİ VEYA HİÇBİR YARDIM olursa olsun) sadece 0.400 saniye sürer.

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)

İşte tek bir sorguda EXPLAIN:

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

Ve işte KATILIM İÇİN AÇIKLAMA:

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                     

Bu konuda yardım büyük mutluluk duyacağız. :)

DÜZENLE:

Tutarsız sonuç alıyorum. Örneğin convert_tz'i kaldırır ve sendika dışında saat dilimi almaya çalışırsam çok hızlı sonuçlar alırım, ancak sonucu yeniden adlandırırsam, otomatik olarak aynı düşük performans sorgusuna iner:

SELECT
    *,
    GetCarrierTimezone(carrier_id) timezone
FROM
(

bu 0.374s alır

SELECT
    *,
    GetCarrierTimezone(carrier_id)
FROM
(

Bu 0.078 alır (çoğunlukla db makineme gecikme) ..


En basit olanı ayrı ayrı çalıştırmak ve sonuçları uygulamada birleştirmektir.
ypercubeᵀᴹ

merhaba @ypercube, aklımı geçti :) ama bunu yapmak ve bu kodu korumak çok çirkin. Ayrıca ben hala php sonuçları sıralamak zorunda.
helderjsm

İstediğim sıra ile 2 sorgu çalıştırmak demekti. O zaman sadece php (sıralama) birleştirmek gerekir.
ypercubeᵀᴹ

1
Sıralama doğrusal değildir. Sorgu 1'in sonucu 2 sorgusu sonuçları arasında olabilir.
helderjsm

1
@ Ypercube sonuçları örtüşmüyor varsayıyor olduğunu sanmıyorum: bir 'birleştirme' php uygulamak için bir tür daha ucuz / daha kolay. Tabii ki mümkünse SQL'de sorunu düzeltmek çok daha iyi bir çözüm olurdu :)
Jack diyor ki topanswers.xyz

Yanıtlar:


1

Ben orada ORDER BY nedeniyle bu olmasını beklenir.

Bunu Birliğin ilk bölümünde deneyin:

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

Ve bu ikinci bölümde:

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

Ve sonra yerini ORDER BYile

ORDER BY alertFoo

Başka bir deyişle, IF gereğini sırayla kaldırın.


Merhaba Thomas, Öncelikle tekrarın için teşekkür ederim. Daha önceki bir yazıda söylediğim gibi bu bir süre önce düzeltildi. Mesele şu ki, uyarı 1 ve uyarı 2 arasındaki ayrım gerekiyordu. Her durumda, sipariş birleşim sonucu değil, birleştirmeler sonucu yapılır. Sorgunun yavaşlığını haklı çıkarmak için o kadar çok sonuç yoktu.
helderjsm

0

Çok çok benzer bir durumda, mysql işlem listesinden 'geçici tabloya kopya' çok kötü davranış (ne kopyalama? Bilmiyorum) fark ettim. Ben mysql sorgulama için 'en iyi yaklaşım' cazip olduğunu düşünüyorum, ancak bu durumda başarısız oldu, bu yüzden '2-sorgu sonuçları' birleştirme 'için kod kullanarak iyi çalıştı.


Merhaba realtebo, Giriş için teşekkürler. Bu şimdi biraz eski, ama hatırladığım kadarıyla tutarsızlık, mysql'in bazı sonuçları nasıl önbelleğe aldığıydı, diğerleri değil. Sonunda, indeksleri daha verimli kılan ayrı bir tabloda ihtiyacım olan değerleri takip ederek sorguyu daha verimli bir şekilde yeniden oluşturdum.
helderjsm

0

Union sql'in daha yavaş çalışmasının temel nedeni, birliğin mysqld'in dahili geçici bir tablo oluşturmasına neden olmasıdır. Bir UNION ALL için yalnızca bir tablo ve UNION DISTINCT için bir dizini (kopyaları kaldırmak için) içeren bir tablo oluşturur.

Bu yardımcı olur umarım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.