2010-04-07 3 views
2

Я работаю над кратчайшим путем * алгоритмом в java с mysql db. Я выполняю следующий SQL Query примерно 300 раз в программе, чтобы найти маршруты соединений из базы данных из 10 000 соединений шины. Выполнение запроса занимает около 6-7 секунд. Любые предложения о том, как я могу ускорить это или какие-либо идеи по другому методу, который я могу использовать? БлагодаряУскорить несколько запросов SQL JDBC?

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

Спасибо за все ваши ответы. Да, у меня есть граф с Stations как узлы. Я обновил вопрос с полным кодом методов, которые я использую. Метод getNeighbours() передается узлу с наименьшим значением ((стоимость достижения узла) + (расстояние до узла цели)) с помощью PriorityQueue. Вот почему я должен запрашивать базу данных каждый раз, когда это новый узел поверх очереди приоритетов. Я не могу предсказать, какой узел будет рядом с первым в очереди приоритетов, пока я не получу доступ к ним соседей узлов. Я не могу кэшировать данные о прекращении подключения, поскольку он содержит 10 000+ соединений. Все предложения? – patrickandroid

+0

Не используйте БД. Загрузите все данные в объект «graph» в основной памяти. В моем проекте у меня есть миллионы узлов (и еще больше ребер) на графике и какой-то алгоритм Дейкстры, который работает на всем этом, и я получаю время работы намного меньше секунды. – jutky

+0

Этот код JDBC пропускает ресурсы. Исправьте его как можно скорее. – BalusC

ответ

0

В общем, если ваш запрос является медленным и дорогим, попробуйте кэширование результатов где-то, так что на следующем поиске он будет быстро извлекаются из кэша. Таким образом, вы бы (дорого) вычислили соединение между точками A и B, сохраните весь результирующий набор в другой (временной = кеше) таблице в базе данных с определенным временем жизни, поэтому в течение следующих X часов/дней (или до тех пор, пока маршруты не изменятся) вы можете получить маршрут от A до B из этой таблицы кэша.

+0

спасибо, что я кэшировал все данные соединения в hashTable, это мешает мне постоянно подключаться к db – patrickandroid

0

Вы можете использовать предложение IN для запуска запроса только один раз - выберите * из соединений, где Connections.From_Station_stopID IN (значение1, значение2, ...).

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. Если только константа в пункте WHERE для From_Station_stopID изменяется каждый раз, использовать параметризованные, подготовленный запрос так что база данных не должна анализировать запрос и каждый раз строить путь выполнения или комбинировать запросы с одним, используя WHERE From_Station_stopID IN (value1, value2, ...)
  4. Если вы повторяете одни и те же запросы часто, убедитесь, что MySQL использует кеширование запросов

Если вы указали нам остальную часть кода, где это цикл, чтобы вызвать запрос 300 раз, мы могли бы помочь дальше.

В общем, я бы сказал, что если вы каждый раз вычисляете кратчайший путь, вместо этого вы должны построить таблицу, которая работает как сетка, с расстояниями маршрута, предварительно рассчитанными для каждой остановки, или даже целыми маршрутами, предварительно рассчитанными из каждый остановка.

Смежные вопросы