簡體   English   中英

我的 SQL - 嘗試優化查詢返回更多行

[英]My SQL - trying to optimize Query returns more rows

我有一個從我以前的同事那里繼承的查詢,但我需要對其進行優化。

此查詢返回 72 行。

SELECT  id, contract_no, customer, address, cm_mac, aps
    FROM  
    (
        SELECT  *
            from  new_installed_devices
            where  insert4date >='2018-10-28'
              AND  insert4date <='2018-10-28'
              AND  install_mark<2
    ) as d1
    left join  
    (
        SELECT  *
            from  
            (
                SELECT  contract_no AS c_no, cm_mac AS c_mc, MIN(tstamp) as time2,
                        sum(1) as aps
                    from  devices_change
                    where  contract_no in (
                        SELECT  distinct(contract_no)
                            from  devices_change
                            where  tstamp >= '2018-10-28 06:59:59'
                              AND  tstamp <= '2018-10-29 07:00:00'
                          )
                    group by  contract_no, cm_mac 
            ) as mtmbl
            where  mtmbl.time2 >= '2018-10-28 06:59:59'
              and  mtmbl.time2 <= '2018-10-29 07:00:00' 
    ) as tmp  ON d1.contract_no=tmp.c_no
    where  aps>0
    group by  contract_no, customer, address, cm_mac;

執行需要 20 秒。 我重寫它,試圖優化它,但在這種情況下,我有 75 行(返回 3 行額外的行),但結果在 2 秒內顯示。

我已經這樣做了(唯一的區別是在一個子查詢中):

SELECT  id, contract_no, customer, address, cm_mac, aps
    FROM  
    (
        SELECT  *
            from  new_installed_devices
            where  insert4date >='2018-10-28'
              AND  insert4date <='2018-10-28'
              AND  install_mark<2
    ) as d1
    left join  
    (
        SELECT  *
            from  
            (
                SELECT distinct
                        (contract_no) AS c_no,
                        cm_mac AS c_mc, MIN(tstamp) as time2,
                        sum(1) as aps
                    from  devices_change
                    where  tstamp >= '2018-10-28 06:59:59'
                      AND  tstamp <= '2018-10-29 07:00:00'
                    group by  contract_no, cm_mac 
            ) as mtmbl
            where  mtmbl.time2 >= '2018-10-28 06:59:59'
              and  mtmbl.time2 <= '2018-10-29 07:00:00' 
    ) as tmp  ON d1.contract_no=tmp.c_no
    where  aps>0
    group by  contract_no, customer, address, cm_mac;

就像您看到的那樣,在我的情況下,我並沒有太大變化,但我仍然得到了更多的行,它應該是結果。 有人可以告訴我為什么我的第二個查詢沒有返回完全正確的結果。 我嘗試了很多東西來優化但沒有成功。 非常感謝!!!

  • 當您不需要所有列時,不要使用SELECT * 看起來contract_nodl唯一需要的列,因此來自new_installed_devices
  • 有什么理由以這種奇怪的方式測試insert4date的相等性嗎?
  • 推薦INDEX(insert4date, install_mark, dl) (按順序)
  • 盡量避免構造IN ( SELECT ... ) 通常最好使用EXISTSLEFT JOIN
  • 別說DISTINCT(contract_no), ... -- DISTINCT不是函數; 它的效果適用於整個表達式集。 擺脫DISTINCT因為GROUP BY有這種效果。
  • 推薦INDEX(contract_no, cm_max, tstamp)INDEX(contract_no, cm_max, tstamp)順序)
  • mtmbl.time2 上的測試是多余的,因為`MIN(tstamp) 已經被限制在那個(1 天 + 2 秒)時間范圍內。
  • 請提供SHOW CREATE TABLE
  • 您可以將 FROM 子句中的第一個子查詢替換為對表new_installed_devices的直接引用,以及 WHERE 子句中的某些條件。 在舊版本中,MySQL 不能很好地處理子查詢,所以盡量避免在 FROM 子句中使用它們(特別是如果你有超過 1 或 2 個)。
  • mtmbl.time2的范圍條件可以折疊到子查詢的 HAVING 子句中,以確保您盡快過濾該數據,而無需使用該子查詢創建大型臨時表。
  • 你能提供這些表的 SHOW CREATE TABLE 和查詢的 EXPLAIN 嗎? 它可能會有所幫助。

在猜測 MySQL 會在此處選擇的順序時,您可以嘗試添加這些索引並運行以下查詢,看看是否效果更好。 我將上面的建議應用於下面的查詢(希望我對列來源的猜測是正確的,否則請相應地修復所有內容):

ALTER TABLE `devices_change` ADD INDEX `devices_change_idx_no_mac_tstamp` (`contract_no`,`cm_mac`,`tstamp`);
ALTER TABLE `devices_change` ADD INDEX `devices_change_idx_tstamp_no` (`tstamp`,`contract_no`);
ALTER TABLE `new_installed_devices` ADD INDEX `new_installed_device_idx_no_insert4date` (`contract_no`,`insert4date`);

查詢:

SELECT
        new_installed_devices.id,
        new_installed_devices.contract_no,
        new_installed_devices.customer,
        new_installed_devices.address,
        new_installed_devices.cm_mac,
        new_installed_devices.aps 
    FROM
        new_installed_devices AS d1 
    LEFT JOIN
        (
            SELECT
                * 
            FROM
                (SELECT
                    devices_change.contract_no AS c_no,
                    devices_change.cm_mac AS c_mc,
                    MIN(devices_change.tstamp) AS time2,
                    sum(1) AS aps 
                FROM
                    devices_change 
                WHERE
                    devices_change.contract_no IN (
                        SELECT
                            DISTINCT (devices_change.contract_no) 
                        FROM
                            devices_change 
                        WHERE
                            devices_change.tstamp >= '2018-10-28 06:59:59' 
                            AND devices_change.tstamp <= '2018-10-29 07:00:00'
                    ) 
                GROUP BY
                    devices_change.contract_no,
                    devices_change.cm_mac 
                HAVING
                    devices_change.time2 >= '2018-10-28 06:59:59' 
                    AND devices_change.time2 <= '2018-10-29 07:00:00' 
                ORDER BY
                    NULL) AS mtmbl) AS tmp 
                    ON d1.contract_no = tmp.c_no 
            WHERE
                aps > 0 
                AND d1.insert4date >= '2018-10-28' 
                AND d1.insert4date <= '2018-10-28' 
                AND d1.install_mark < 2 
            GROUP BY
                new_installed_devices.contract_no,
                new_installed_devices.customer,
                new_installed_devices.address,
                new_installed_devices.cm_mac 
            ORDER BY
                NULL

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM