2010-04-07 28 views
2

我正在使用mysql數據庫處理java中的最短路徑a *算法。我在程序中執行了大約300次以下SQL查詢,以從10,000個總線連接的數據庫中找到路由連接。大約需要6-7秒來執行查詢300次。任何關於如何加快速度的建議或關於我可以使用的其他方法的任何建議?由於加速多個JDBC SQL查詢?

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; 
} 
+0

感謝您的所有答案。是的,我有一個圖表作爲節點。我已經用我使用的完整代碼更新了這個問題。 getNeighbours()方法通過PriorityQueue的方式通過節點(((到達節點的成本)+(到目標節點的距離))的最低值。這就是爲什麼我必須每次查詢數據庫時,他們都是優先級隊列之上的新節點。我無法預測哪個節點將成爲優先級隊列中的第一個,直到我訪問它的節點鄰居。我無法緩存停止連接數據,因爲它包含10,000多個連接。有任何建議? – patrickandroid 2010-04-07 11:28:58

+0

請勿使用數據庫。將所有數據加載到主內存中的「圖形」對象。在我的項目中,圖中有數百萬個節點(甚至更多的邊),以及某種運行於此的Dijkstra算法,而且我的運行時間少於一秒鐘。 – jutky 2010-04-07 12:05:40

+0

此JDBC代碼泄露資源。儘快修復。 – BalusC 2010-04-07 14:07:08

回答

0

一般情況下,如果您的查詢速度慢,價格昂貴,嘗試某處緩存結果,因此下一次查找它會迅速從緩存中檢索。因此,您將(昂貴地)計算A點和B點之間的連接,將整個結果集存儲在數據庫中具有定義的生命週期的其他(臨時=緩存)表中,以便在接下來的X小時/天(或直到路由更改)您可以從此緩存表中檢索從A到B的路由。

+0

謝謝我將所有連接數據緩存在一個hashTable中,這可以防止我連續連接到db – patrickandroid 2010-04-07 21:53:35

0

您可以使用IN子句爲了僅運行一次查詢 - 從連接中選擇* from Connections其中Connections.From_Station_stopID IN(value1,value2,...)。

1

據我所知,你有一個圖表作爲節點和連接作爲邊緣。

嘗試創建一些代表該圖的對象(它可以是最簡單的情況下的矩陣)並在該對象上執行搜索。那麼你就不需要對你的數據庫進行300次調用,這從性能的角度來看是非常昂貴的。

1

首先,您應該使用PreparedStatement而不是普通查詢,並且每次都要執行stmt.setInt(1, StopId)

另外,最好選擇您感興趣的特定字段,而不是select *

這些只是一般的JDBC提示,它們可能不會對運行時產生巨大影響,但值得一做。

之後,我會嘗試調查表索引,以確保基於From_Station_stopID的查詢確實以儘可能快的速度執行。

如果是,並且唯一的開銷是單獨調用數據庫的數量,那麼下一步可能是嘗試合併查詢,可能是將其設置爲select ... from connections where From_Station_stopID in (..., ..., ...)

根據表的大小,您可能只是想提前將所有內容加載到內存中(也許作爲HashMap),然後在每次迭代中都不需要訪問數據庫。

總之,這取決於問題的不同參數,您需要檢查哪種解決方案最適合您。

2
  1. 確保您有connections.From_Station_stopID
  2. 代替SELECT *索引,只選擇列,你需要
  3. 如果只有不斷在From_Station_stopIDWHERE子句中的時間變化,使用參數,編寫查詢以便數據庫不必每次都解析查詢並構建執行路徑,或將查詢合併爲一個使用WHERE From_Station_stopID IN (value1, value2, ...)
  4. 如果您經常重複相同的查詢,請確保MySQL正在使用查詢緩存

如果您向我們展示了其餘的代碼,它將循環調用查詢300次,我們可能會進一步提供幫助。一般來說,如果你每次計算最短路徑,你應該建立一個像網格一樣工作的表格,爲每個站點預先計算的路線距離,甚至預先計算的全部路線每站。