加速多个JDBC SQL查询?

时间:2010-04-07 09:35:53

标签: java jdbc mysql performance

我正在使用mysql db在java中使用最短路径a *算法。我正在程序中执行以下SQL查询大约300次,以从10,000个总线连接的数据库中查找路由连接。执行查询需要大约6-7秒。关于我如何加快这一点或任何关于我可以使用的不同方法的想法的任何建议?感谢

private HashMap<Coordinate,Node> closedNodes;
private PriorityQueue<Node> openNodes;

..
private List<Coordinate> calculatePath() 
{
    //While there are nodes in the open list
    while (!openNodes.isEmpty()) 
    {
        //Get the node with the lowest gVal+hVal
        Node node = openNodes.poll();
        //Add it to the closed list
        closedNodes.put(node);
        //If it is not the goal node
        if (!node.equals(goal)) 
        {   
            //Get all the neighbours and Create neighbour node
            List<Node> neighbours = helper.getNeighbours(node, goal);
            //For each neighbour
            for (Node neighbourNode : neighbours) 
            {
                //Check if the neighbour is in the list of open nodes
                boolean isInOpen = checkOpenNodes(neighbourNode);
                //If it is not in the open nodes and not in the closed nodes
                if ((!closedNodes.containsKey(neighbourNode))&& (!isInOpen)) 
                {
                    //Add it to the list of open nodes
                    openNodes.add(neighbourNode);
                }
            }
        }
        else 
        {
            // We found the path
            path = backTrackPath(node);
            break;              
        }
    }
    return path;

/**
 * Gets the list of valid Nodes that are possible to travel to from <b>Node</b>
 * @param stopNode Node to find neighbours for
 * @param goal End Node
 * @return list of neighbour Nodes
 */
public ArrayList<Node> getNeighbours(Node stopNode, Node goal) 
{
    ArrayList<Node> neighbours = new ArrayList<Node>(); 
    Node neighbourNode;     
    //get neighbours connected to stop  
        try {
            ResultSet rs = stmt.executeQuery("select To_Station_id, To_Station_routeID, To_Station_stopID," +
                    "To_Station_lat, To_Station_lng, Time from connections  where Connections.From_Station_stopID ="
                    +stopNode.getCoord().getStopID()+" ORDER BY Connections.Time");

            rs = stmt.getResultSet();
            while (rs.next()) {
                int id = rs.getInt("To_Station_id");
                String routeID = rs.getString("To_Station_routeID");
                String stopID = rs.getString("To_Station_stopID");
                String stopName = rs.getString("To_Station_stopName");
                Double lat = rs.getDouble("To_Station_lat");
                Double lng = rs.getDouble("To_Station_lng");
                int time = rs.getInt("Time");
                neighbourNode = new Node(id, routeID, stopID, stopName, lat, lng);
                neighbourNode.prev = stopNode;
                neighbourNode.gVal = stopNode.gVal + time;
                neighbourNode.hVal = heuristic.calculateHeuristic(neighbourNode, goal);
                neighbours.add(neighbourNode);
            }
        }
    catch (SQLException e) {
        e.printStackTrace();
    }
    return neighbours;
}

5 个答案:

答案 0 :(得分:2)

  1. 确保您在connections.From_Station_stopID
  2. 上有索引
  3. 而不是SELECT *,只选择您需要的列
  4. 如果WHERE From_Station_stopID子句中的常量每次都更改,请使用参数化的准备好的查询,以便数据库不必每次都解析查询并构建执行路径,或使用WHERE From_Station_stopID IN (value1, value2, ...)
  5. 将查询合并为一个
  6. 如果您经常重复相同的查询,请确保MySQL使用查询缓存
  7. 如果你向我们展示了剩下的代码,那么它循环调用查询300次,我们可能会进一步提供帮助。

    一般来说,如果你每次计算最短路径,你应该建立一个像网格一样工作的表格,每个站点预先计算路由距离,甚至预先计算每个路径的整个路径。停止。

答案 1 :(得分:1)

据我所知,你有一个图表,其中Stations为节点,Connections为边缘。

尝试创建一些表示该图形的对象(在最简单的情况下它可以是矩阵)并对该对象执行搜索。然后,从性能的角度来看,您不需要对数据库进行300次调用,这些调用非常昂贵。

答案 2 :(得分:1)

首先,您应该使用PreparedStatement而不是普通查询,并且每次只执行stmt.setInt(1, StopId)

此外,最好选择您感兴趣的特定字段,而不是select *

这些只是一般的JDBC技巧,可能不会对运行时产生巨大影响,但值得做。

之后,我会尝试调查表索引,以确保基于From_Station_stopID的查询确实执行得尽可能快。

如果是,并且唯一的开销是对数据库的单独调用量,下一步可能是尝试组合查询,可能将其设为select ... from connections where From_Station_stopID in (..., ..., ...)

根据表的大小,您可能只想将整个事物预先加载到内存中(可能作为HashMap),然后您不需要在每次迭代时都转到数据库。

简而言之,它在很大程度上取决于问题的不同参数,您需要检查哪种解决方案最适合您。

答案 3 :(得分:0)

通常,如果您的查询速度慢且成本高,请尝试在某处缓存结果,因此在下一次查找时,它将从缓存中快速检索。因此,您(昂贵地)计算A点和B点之间的连接,将整个结果集存储在具有定义生命周期的数据库中的其他(临时=缓存)表中,因此对于下一个X小时/天(或直到路由更改)您可以从此缓存表中检索从A到B的路由。

答案 4 :(得分:0)

您可以使用IN子句只运行一次查询 - 从Connections.From_Station_stopID IN(value1,value2,...)的连接中选择*。