Ускорить несколько запросов JDBC SQL? - PullRequest
2 голосов
/ 07 апреля 2010

Я работаю над алгоритмом * кратчайшего пути в Java с MySQL DB. Я выполняю следующий SQL-запрос около 300 раз в программе, чтобы найти маршрутные соединения из базы данных с 10 000 шинных соединений. Требуется около 6-7 секунд, чтобы выполнить запрос 300 раз. Любые предложения о том, как я могу ускорить это или какие-либо идеи о другом методе, который я могу использовать? Спасибо

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 ]

2 голосов
/ 07 апреля 2010
  1. Убедитесь, что у вас есть индекс для connections.From_Station_stopID
  2. Вместо SELECT *, выберите только нужные вам столбцы
  3. Если в предложении WHERE указана только константадля From_Station_stopID меняется каждый раз, используйте параметризованный, подготовленный запрос, чтобы базе данных не приходилось каждый раз анализировать запрос и строить путь выполнения, или объединять запросы в один, используя WHERE From_Station_stopID IN (value1, value2, ...)
  4. Если вы часто повторяете одни и те же запросы, убедитесь, что MySQL использует кэширование запросов

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

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

1 голос
/ 07 апреля 2010

Для начала вы должны использовать PreparedStatement, а не обычный запрос, и просто каждый раз выполнять stmt.setInt(1, StopId).

Кроме того, лучше выбрать конкретные интересующие вас поля, а нечем select *.

Это всего лишь общие советы JDBC, которые, вероятно, не окажут большого влияния на время выполнения, но их стоит сделать.

После этого я попытаюсь исследоватьиндексы таблиц, чтобы убедиться, что запрос, основанный на From_Station_stopID, действительно выполняется так быстро, как только может.чтобы попытаться объединить запросы, возможно, сделав его select ... from connections where From_Station_stopID in (..., ..., ...).

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

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

1 голос
/ 07 апреля 2010

Насколько я понимаю, у вас есть граф со Станциями в качестве узлов и Соединениями в качестве ребер.

Попробуйте создать какой-нибудь объект, который будет представлять этот граф (это может быть матрица в простейшем случае) и выполнить поиск по этому объекту. Тогда вам не нужно будет делать 300 вызовов в вашу базу данных, что очень дорого с точки зрения производительности.

0 голосов
/ 07 апреля 2010

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

0 голосов
/ 07 апреля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...