2016-09-23 78 views
0

我爲我的一個客戶開發了一個招標管理系統的代碼種類。這是一段代碼:優化幫助:SQL查詢顯示每個國家的最低價格

try { 
    Connection con = Mycon.getConnection(); 
    PreparedStatement ps = con.prepareStatement("TRUNCATE tempcalcplan"); 
    ps.executeUpdate(); 
    ps.clearBatch(); 
    ps = con.prepareStatement("INSERT INTO tempcalcplan SELECT v.conid,c.conname, v.rate, v.venid FROM venprices v LEFT JOIN country c ON c.conid = v.conid WHERE (v.conid, v.rate) IN (SELECT v.conid, MIN(v.rate) FROM venprices v GROUP BY v.conid) GROUP BY v.conid"); 
    ps.executeUpdate(); 
    ps.clearBatch(); 
    ps = con.prepareStatement("select * from tempcalcplan"); 

    ResultSet rs = ps.executeQuery(); 
    jTable1.setModel(DbUtils.resultSetToTableModel(rs)); 
} catch(Exception e){ 
    e.printStackTrace(); 
} 

這段代碼被設計成用作:

  1. 清空表tempcalcplan(假定先前的結果被存儲。)
  2. 生成期望的數據與在兩張不同的表的幫助下(表格如下所示)並將其存儲在tempcalcplan表中
  3. 在jTable上顯示tempcalcplan表的結果。

這裏是countrytempcalcplan表。

  1. country(含30000條記錄)

    +---------+-------------+------+-----+---------+-------+ 
    | Field | Type  | Null | Key | Default | Extra | 
    +---------+-------------+------+-----+---------+-------+ 
    | conid | int(10)  | NO | PRI | NULL |  | 
    | conname | varchar(50) | YES |  | NULL |  | 
    +---------+-------------+------+-----+---------+-------+ 
    
  2. tempcalcplan(包含1,80,000+紀錄)

    +---------+-------------+------+-----+---------+-------+ 
    | Field | Type  | Null | Key | Default | Extra | 
    +---------+-------------+------+-----+---------+-------+ 
    | conid | int(10)  | NO | PRI | NULL |  | 
    | conname | varchar(50) | YES |  | NULL |  | 
    | rate | double  | YES |  | NULL |  | 
    | venid | varchar(50) | YES |  | NULL |  | 
    +---------+-------------+------+-----+---------+-------+ 
    
  3. venprices

    +-------+--------------+------+-----+---------+-------+ 
    | Field | Type   | Null | Key | Default | Extra | 
    +-------+--------------+------+-----+---------+-------+ 
    | conid | int(10)  | NO | PRI | NULL |  | 
    | rate | double  | YES |  | NULL |  | 
    | venid | varchar(50) | NO | PRI |   |  | 
    +-------+--------------+------+-----+---------+-------+ 
    

結果最多需要12-15分鐘才能顯示在jTable中。 我想把它縮短到1-2分鐘。

+0

聞起來像[_Groupwise max_](https:// mariadb。com/kb/en/mariadb/groupwise-max-in-mariadb /) - 該鏈接顯示如何有效地執行此操作。 –

回答

2

這是大概花費時間最多的查詢:

INSERT INTO tempcalcplan 
    SELECT v.conid, c.conname, v.rate, v.venid 
    FROM venprices v LEFT JOIN 
     country c 
     ON c.conid = v.conid 
    WHERE (v.conid, v.rate) IN (SELECT v.conid, MIN(v.rate) FROM venprices v GROUP BY v.conid) GROUP BY v.conid"); 

我的猜測是,WHERE條款引起的問題。嘗試將此移動到FROM子句:

SELECT v.conid, c.conname, v.rate, v.venid 
    FROM venprices v LEFT JOIN 
     country c 
     ON c.conid = v.conid JOIN 
     (SELECT v.conid, MIN(v.rate) as rate 
      FROM venprices v 
      GROUP BY v.conid 
     ) vr 
     ON v.conid = vr.conid and v.rate = vr.rate; 

我認爲您的索引對此查詢設置良好。

+0

我沒有設置任何索引。說實話,我其實不知道如何使用索引。 –

+0

@ArpitPorwal。 。 。主鍵生成索引。 –

+0

謝謝@GordonLinoff,經過一些修改,完整的操作在不到2秒的時間內完成。但是當我在查詢之前追加'insert into tempcalcplan'時,它不會被插入到表中。 –

1

Gordon's query的確看起來像是對當前使用的主要改進。

SELECT v.conid, c.conname, v.rate, v.venid 
FROM venprices v LEFT JOIN 
    country c 
    ON c.conid = v.conid JOIN 
    (SELECT v.conid, MIN(v.rate) as rate 
     FROM venprices v 
     GROUP BY v.conid 
    ) vr 
    ON v.conid = vr.conid and v.rate = vr.rate; 

我不確定你已經有索引需要。在MySQL中運行以下命令:

ALTER TABLE `venprices` ADD INDEX `RatesPerConid` (`conid`,`rate`) 

創建該索引後,您應該看到性能急劇提高。注RatesPerConid是索引的名稱。你可以改變它到任何你喜歡的。

警告:如果有可能具有相同的最低rate對於給定conid的多個實例,你可能需要在查詢(不與GROUP BY查詢)的頂部改到SELECTSELECT DISTINCT