2016-09-23 68 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