簡體   English   中英

MySQL - 查詢獲取速度非常慢

[英]MySQL - query fetching very slow

CREATE TABLE `offers` (
  `id` mediumint(8) unsigned NOT NULL auto_increment,
  `cap_id` varchar(255),
  `deposit_value` varchar(255) default NULL,
  `term` varchar(255) default NULL,
  `annual_mileage` varchar(255) default NULL,
  `finance_type` varchar(255) default NULL,
  `monthly_payment` mediumint default NULL,
  `stock` varchar(255) default NULL,
  PRIMARY KEY (`id`)
) AUTO_INCREMENT=1;

INSERT INTO `offers` (`cap_id`,`deposit_value`,`term`,`annual_mileage`,`finance_type`,`monthly_payment`,`stock`) VALUES ("93897","6","24","12000","B",363,"0"),("90626","1","24","12000","P",810,"0"),("93607","6","36","25000","B",172,"1"),("35877","1","48","10000","B",678,"1"),("77134","3","24","10000","P",454,"0"),("47080","6","36","10000","B",737,"0"),("46392","3","24","30000","P",261,"0"),("21418","3","36","20000","B",390,"1"),("80175","9","48","10000","B",713,"1"),("91487","6","48","12000","P",778,"1");
INSERT INTO `offers` (`cap_id`,`deposit_value`,`term`,`annual_mileage`,`finance_type`,`monthly_payment`,`stock`) VALUES ("18311","9","24","20000","B",384,"0"),("41740","9","24","12000","P",674,"1"),("69030","9","24","10000","P",518,"0"),("53342","3","36","8000","B",746,"1"),("65566","6","36","30000","P",145,"1"),("63172","6","48","5000","P",698,"1"),("79712","1","48","30000","B",330,"1"),("90505","1","36","8000","B",458,"0"),("42393","1","36","20000","B",363,"1"),("70454","9","24","5000","B",673,"1");
INSERT INTO `offers` (`cap_id`,`deposit_value`,`term`,`annual_mileage`,`finance_type`,`monthly_payment`,`stock`) VALUES ("81215","1","48","8000","B",472,"0"),("76538","3","24","15000","B",226,"0"),("05094","9","36","12000","P",721,"1"),("57363","9","48","5000","B",777,"1"),("23233","1","48","12000","B",381,"0"),("40542","3","48","12000","P",610,"0"),("63824","3","24","12000","B",761,"1"),("17686","3","24","5000","P",893,"1"),("57669","9","48","30000","P",805,"0"),("21864","1","24","25000","P",530,"0");
INSERT INTO `offers` (`cap_id`,`deposit_value`,`term`,`annual_mileage`,`finance_type`,`monthly_payment`,`stock`) VALUES ("48360","3","48","12000","P",159,"0"),("88614","3","48","20000","B",730,"0"),("17693","1","24","10000","B",298,"0"),("34049","6","48","20000","B",728,"0"),("15038","9","24","10000","P",720,"1"),("31809","1","36","20000","P",237,"0"),("49277","9","48","25000","P",235,"1"),("54607","1","24","12000","P",661,"1"),("65098","1","48","20000","P",548,"1"),("76440","9","48","10000","P",495,"1");

CREATE TABLE `offers_lowest` (
  `id` mediumint(8) unsigned NOT NULL auto_increment,
  `date` DATE,
  `cap_id` varchar(255),
  `deposit` varchar(255) default NULL,
  `term` varchar(255) default NULL,
  `mileage` varchar(255) default NULL,
  `finance_type` varchar(255) default NULL,
  `lowest_price` mediumint default NULL,
  `stock` varchar(255) default NULL,
  PRIMARY KEY (`id`)
) AUTO_INCREMENT=1;

INSERT INTO `offers_lowest` (`date`,`cap_id`,`deposit`,`term`,`mileage`,`finance_type`,`lowest_price`,`stock`) VALUES ("2021-04-09","93897","6","24","12000","B",363,"0"),("2021-04-010","90626","1","24","12000","P",810,"0"),("2021-04-010","93607","6","36","25000","B",172,"1"),("2021-04-10","35877","1","48","10000","B",678,"1"),("2021-04-11","77134","3","24","10000","P",454,"0"),("2021-04-11","47080","6","36","10000","B",737,"0"),("2021-04-11","46392","3","24","30000","P",261,"0"),("2021-04-11","21418","3","36","20000","B",390,"1"),("2021-04-12","80175","9","48","10000","B",713,"1"),("2021-04-12","91487","6","48","12000","P",778,"1");
INSERT INTO `offers_lowest` (`date`,`cap_id`,`deposit`,`term`,`mileage`,`finance_type`,`lowest_price`,`stock`) VALUES ("2021-04-09","18311","9","24","20000","B",384,"0"),("2021-04-010","41740","9","24","12000","P",674,"1"),("2021-04-010","69030","9","24","10000","P",518,"0"),("2021-04-10","53342","3","36","8000","B",746,"1"),("2021-04-11","65566","6","36","30000","P",145,"1"),("2021-04-11","63172","6","48","5000","P",698,"1"),("2021-04-11","79712","1","48","30000","B",330,"1"),("2021-04-11","90505","1","36","8000","B",458,"0"),("2021-04-12","42393","1","36","20000","B",363,"1"),("2021-04-12","70454","9","24","5000","B",673,"1");
INSERT INTO `offers_lowest` (`date`,`cap_id`,`deposit`,`term`,`mileage`,`finance_type`,`lowest_price`,`stock`) VALUES ("2021-04-09","81215","1","48","8000","B",472,"0"),("2021-04-09","76538","3","24","15000","B",226,"0"),("2021-04-010","05094","9","36","12000","P",721,"1"),("2021-04-10","57363","9","48","5000","B",777,"1"),("2021-04-11","23233","1","48","12000","B",381,"0"),("2021-04-11","40542","3","48","12000","P",610,"0"),("2021-04-11","63824","3","24","12000","B",761,"1"),("2021-04-11","17686","3","24","5000","P",893,"1"),("2021-04-12","57669","9","48","30000","P",805,"0"),("2021-04-12","21864","1","24","25000","P",530,"0");
INSERT INTO `offers_lowest` (`date`,`cap_id`,`deposit`,`term`,`mileage`,`finance_type`,`lowest_price`,`stock`) VALUES ("2021-04-09","48360","3","48","12000","P",159,"0"),("2021-04-09","88614","3","48","20000","B",730,"0"),("2021-04-010","17693","1","24","10000","B",298,"0"),("2021-04-10","34049","6","48","20000","B",728,"0"),("2021-04-11","15038","9","24","10000","P",720,"1"),("2021-04-11","31809","1","36","20000","P",237,"0"),("2021-04-11","49277","9","48","25000","P",235,"1"),("2021-04-11","54607","1","24","12000","P",661,"1"),("2021-04-12","65098","1","48","20000","P",548,"1"),("2021-04-12","76440","9","48","10000","P",495,"1");

CREATE INDEX idx_profile_grouping ON offers (cap_id, deposit_value, term, annual_mileage);

CREATE INDEX idx_specials_query ON offers_lowest (cap_id, deposit, term, mileage);

SQLFiddle

所以,我正在嘗試加入兩個表 - 一個是我們平台上的活動報價列表(我們是一個汽車租賃比較網站),另一個是自定義表,它每天記錄每輛車的最佳價格(cap_id),以及每個可能的財務狀況,即 9 個月的存款價值、24 個月的合同和每年 8,000 英里等。

這是為了確定什么是“好”價格的最終目標,output 包含MIN(offers.monthly_payment)MIN(offers_lowest.lowest_price)以及計算的百分比差異,歷史價格數據取自 7 -day 日期范圍不包括當天。

offers_lowest是從每天的offers中匯總的,找到按以下條件分組的最低monthly_payment付款: cap_id, deposit_value, term, annual_mileage, finance_type

到目前為止,這是我想出的:

SELECT 
    s.cap_id,
    s.deposit,
    s.term,
    s.mileage,
    s.best_price,
    f.previous_best,
    (( s.best_price - f.previous_best ) / f.previous_best ) * 100 AS difference,
    s.stock
FROM
    (SELECT
        o.cap_id,
        o.deposit_value as deposit,
        o.term,
        o.annual_mileage as mileage,
        o.finance_type,
        MIN(o.monthly_payment) AS best_price,
        o.stock,
        o.brand_id
    FROM
        offers o USE INDEX(idx_profile_grouping)
    WHERE o.finance_type = 'P'
    GROUP BY o.cap_id, o.deposit_value, o.term, o.annual_mileage
    ) s 
    
INNER JOIN

    (SELECT
        ol.cap_id,
        ol.deposit,
        ol.term,
        ol.mileage,
        MIN(lowest_price) as previous_best
    FROM
        offers_lowest ol USE INDEX(idx_specials_query)
    WHERE finance_type = 'P'
        AND ol.date > CURDATE() - INTERVAL 7 DAY
        AND ol.date <= CURDATE() - INTERVAL 1 DAY
    GROUP BY ol.cap_id, ol.deposit, ol.term, ol.mileage
    ) f ON s.cap_id = f.cap_id AND s.deposit = f.deposit AND s.term = f.term AND s.mileage = f.mileage
GROUP BY s.cap_id, s.deposit, s.term, s.mileage

問題在於速度。 當我單獨運行任一子查詢時,運行時間 <0.1 秒,然后獲取大約 75 秒。 當我運行整個過程時,它會一直運行直到我停止它(>10 分鍾)。

這些索引是我在 cap_id、deposit、term 和 mileage 字段(兩個表)上創建的,以試圖加快速度。

解釋返回這個:

# ID 選擇類型 桌子 分區 類型 可能的鍵 鑰匙 key_len 參考 過濾 額外的
1 基本的 全部 965741 100.00 使用哪里; 使用臨時的; 使用文件排序
1 基本的 參考 <auto_key0> <auto_key0> 10 f.cap_id f.存款 f.術語 f.里程
3 衍生的 奧爾 指數 idx_specials_query idx_specials_query 13 17386818 5.55 使用哪里
2 衍生的 指數 idx_profile_grouping idx_profile_grouping 10 4800964 50.00 使用哪里

並且 SHOW PROFILE 返回這個:

地位 期間
開始 0.000017
檢查查詢緩存以進行查詢 0.000171
檢查權限 0.000006
檢查權限 0.000005
打開表 0.000020
在里面 0.000109
系統鎖 0.000009
優化 0.000005
優化 0.000011
統計數據 0.000033
准備 0.000037
排序結果 0.000007
優化 0.000015
統計數據 0.000017
准備 0.000017
排序結果 0.000012
統計數據 0.000046
准備 0.000021
創建 tmp 表 0.000020
排序結果 0.000007
執行 0.000013
發送數據 0.000012
執行 0.000004
發送數據 68.205032
將 HEAP 轉換為磁盤 0.542756
發送數據 3.132642
執行 0.000019
發送數據 7.968966
將 HEAP 轉換為磁盤 0.746200
發送數據 22.506716
將 HEAP 轉換為磁盤 0.567816
發送數據 4.886870
創建排序索引 2.151519
結尾 0.000019
查詢結束 0.000010
刪除 tmp 表 0.002051
查詢結束 0.000019
收盤 0.000005
刪除 tmp 表 0.001385
收盤 0.000009
刪除 tmp 表 0.002780
收盤 0.000017
釋放物品 0.000069
清理干凈 0.000007
打掃干凈 0.000021

由此看來,我還沒有寫出最有效的查詢..

我們使用 AWS RDS 實例,運行 MySQL 5.7.12。

如果我可以提供任何其他內容來添加背景,請告訴我。

  • FROM ( SELECT... ) JOIN ( SELECT... )效率低下。 嘗試將其中至少一個移到外部SELECT中。 (如果您為JOIN添加合適的索引,這可能會消除“創建排序索引”。它也可能會消除大多數神秘的“發送數據”。)
  • 該日期范圍僅包括 6 個 DATE。
  • 如果一行有 MIN(offers.monthly_payment) 而另一行有 MIN(offers_lowest.lowest_price) 怎么辦?
  • 不要將 VARCHAR(255) 用於數值。 例如,MEDIUMINT 表示里程。 (這可能會消除“將 HEAP 轉換為磁盤”。)
  • 注意 PROFILE 是多么無用; 大多數時候它喜歡說“發送數據”(占總數的 95%)。 我可以確定 4% 並建議修復,見上文。 另外 1% 是不可避免的噪音。
  • 第一個GROUP BY是不合適的,因為它沒有說明為 stock 或 brand_id 賦予哪個值。 如有必要,在找到信息的 rest 后,通過額外的JOIN獲取它們。
  • offers_lowest需求INDEX(finance_type, date)
  • 擺脫“索引提示”( USE INDEX...

暫無
暫無

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

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