ยูเนี่ยนช้า แต่คำถามทั้งสองแยกกันอย่างรวดเร็ว


11

Dunno ทำอะไรกับสิ่งนี้อีก ฉันมีตารางหนึ่งตารางที่มีจุดเริ่มต้นและคอลัมน์หยุดและฉันต้องการส่งคืนผลลัพธ์ของการรวมเข้าด้วยกันโดยเริ่มและหยุดและฉันต้องการความแตกต่างที่ชัดเจนระหว่างทั้งสอง ขณะนี้คำค้นหาทั้งสองทำงานแยกกันอย่างรวดเร็ว:

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 แต่ถ้าฉันรวมเข้าด้วยกันในยูเนี่ยน (ไม่สำคัญว่าจะเป็นยูเนี่ยนทั้งหมดหรือแตกหรืออะไรก็ตาม) มันใช้เวลาประมาณ 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 (ส่วนใหญ่ล่าช้าจาก db ไปยังเครื่องของฉัน) ..


วิธีที่ง่ายที่สุดคือเรียกใช้แยกต่างหากและรวมผลลัพธ์ในแอปพลิเคชัน
ypercubeᵀᴹ

สวัสดี @ypercube นั่นทำให้ฉันใจ :) แต่มันน่าเกลียดที่จะทำและรักษารหัสนั้น นอกจากนี้ฉันยังต้องเรียงลำดับผลลัพธ์เป็น php
helderjsm

ฉันหมายถึงเรียกใช้ 2 แบบสอบถามด้วยการเรียงลำดับที่ต้องการ จากนั้นคุณจะต้องรวมใน php (ไม่มีการเรียงลำดับ)
ypercubeᵀᴹ

1
การเรียงลำดับไม่เป็นเชิงเส้น ผลลัพธ์ของการสืบค้น 1 สามารถอยู่ระหว่างผลลัพธ์ของการสืบค้น 2
helderjsm

1
ฉันไม่คิดว่า @ypercube กำลังสมมติว่าผลลัพธ์ไม่ทับซ้อน: 'การผสาน' นั้นราคาถูกกว่า / ง่ายกว่าการใช้ใน php มาก แน่นอนว่าการแก้ไขปัญหาใน SQL ถ้าเป็นไปได้จะเป็นทางออกที่ดีกว่า :)
4357 Jack Jackson ลอง topanswers.xyz

คำตอบ:


1

ฉันคาดหวังว่าสิ่งนี้จะเกิดขึ้นเพราะคำสั่งซื้อของคุณอยู่ในนั้น

ลองสิ่งนี้ในส่วนแรกของ UNION:

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

และนี่ในส่วนที่สอง:

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

แล้วแทนที่ORDER BYด้วย

ORDER BY alertFoo

กล่าวอีกนัยหนึ่งให้ลบความต้องการ IF ในลำดับโดย


สวัสดีโทมัสก่อนอื่นขอขอบคุณสำหรับการเล่นซ้ำของคุณ เหมือนที่ฉันพูดในโพสต์ก่อนหน้านี้ได้รับการแก้ไขบางครั้งที่ผ่านมา สิ่งที่ฉันต้องการความแตกต่างระหว่างการแจ้งเตือน 1 และการแจ้งเตือน 2 ในกรณีใด ๆ คำสั่งจะทำในผลของการรวมและไม่ได้อยู่ในการเข้าร่วมตัวเอง ไม่มีผลลัพธ์มากมายที่จะพิสูจน์ความช้าของการค้นหา
helderjsm

0

ในกรณีที่คล้ายกันมากฉันสังเกตจากรายการกระบวนการของ mysql พฤติกรรมที่แย่มากของ 'คัดลอกไปยังตารางชั่วคราว' (คัดลอกอะไรฉันไม่รู้) ฉันคิดว่า mysql ล่อลวง 'วิธีการที่ดีที่สุด' สำหรับการสืบค้น แต่ในกรณีนี้ล้มเหลวดังนั้นการใช้รหัสเพื่อ 'ผสาน' ผลการค้นหา 2 ข้อทำงานได้ดี


สวัสดี realtebo ขอบคุณสำหรับการป้อนข้อมูล ตอนนี้มันค่อนข้างเก่า แต่สำหรับสิ่งที่ฉันจำได้ว่าไม่สอดคล้องกันก็เป็นเพราะบางวิธีที่ mysql ทำการแคชผลลัพธ์บางอย่างและไม่ใช่อย่างอื่น ในที่สุดฉันก็สร้างแบบสอบถามขึ้นใหม่อย่างมีประสิทธิภาพยิ่งขึ้นโดยการติดตามค่าที่ฉันต้องการในตารางแยกทำให้ดัชนีมีประสิทธิภาพมากขึ้น
helderjsm

0

เหตุผลหลักสำหรับยูเนี่ยน sql ทำงานช้าลงคือสหภาพทำให้ mysqld เพื่อสร้างตารางชั่วคราวภายใน มันสร้างเพียงตารางสำหรับ UNION ALL และตารางที่มีดัชนี (เพื่อลบรายการที่ซ้ำกัน) สำหรับ UNION DISTINCT

หวังว่านี่จะช่วยได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.