J2EE - PostgreSQL - JDBC - 慢查询

时间:2014-02-11 17:08:44

标签: performance postgresql java-ee jdbc

我遇到了PostgreSQL数据库和JDBC驱动程序(在J2EE应用程序中)的奇怪行为。

为了简单起见,我想说我有两张桌子:

SHIP_MESSAGE(id, datetime, latitude, longitude)
SUBMARINE_MESSAGE(id, datetime, latitude, longitude, immersion)

其中每一个都包含在给定日期时间内发出的消息。现在我必须在网站上重播这些信息。

我使用AJAX每3到500毫秒左右请求一次信息。请求类似于: 从SHIP_MESSAGE中选择ID,日期时间,纬度,经度,其中日期> ='2013-02-11 18:00:00'按日期限制1的顺序;

如果我执行一次(从第一个表中获取消息),则需要大约150毫秒,这很好。但是如果我执行两次(从两个表中获取消息),每个查询需要800到2000毫秒!

所以这很好用:

MessageDAO dao = new MessageDAO(); // Data access object, used to execute my query

Date d1 = new Date();
ShipMessage message = dao.getShipMessageAtDate(date);
Date d2 = new Date();

System.out.println( d2.getTime() - d1.getTime() ); // Around 150 ms

这不是:

MessageDAO dao = new MessageDAO();

Date d1 = new Date();
NavigationMessage message = dao.getShipMessageAtDate(date);
Date d2 = new Date();
SubmarineMessage m2 = dao.getSubmarinMessageAtDate(date);
Date d3 = new Date();

System.out.println( d2.getTime() - d1.getTime() ); // Between 800 and 2000 ms
System.out.println( d3.getTime() - d2.getTime() ); // Between 800 and 2000 ms

我正在使用单例模式来获取连接。如果我创建两个Connection对象,它工作正常(~150 ms),但我不想这样做,因为当客户端太多时我将无法打开足够的连接。

有什么想法吗?

我尝试使用连接只有一个请求包含两个消息的数据,但它也太长(1-3秒),这很奇怪,因为如果我直接在终端中执行它很快。

谢谢!

编辑:

以下是MessageDAO的代码:

public class MessageDAO extends DAO {

    public MessageDAO() { super(); }
    public MessageDAO(Connection connection) { super(connection); }

    public NavSensorsMessage getShipMessageDate(Date date) throws SQLException {

        String sql = "select * from BOAT_MESSAGE where date >= ? order by date limit 1;";

        PreparedStatement ps = _connection.prepareStatement(sql);
        ps.setTimestamp(1, new java.sql.Timestamp(date.getTime()));

        ResultSet result = ps.executeQuery();
        result.next();

        Date datetime = result.getDate("datetime");
        float latitude = result.getFloat("latitude");
        float longitude = result.getFloat("longitude");

        return new ShipMessage(datetime, latitude, longitude);
    }
}

这是DAO课程:

public abstract class DAO {


    // -------------------------------------------------------------------------
    protected Connection _connection;
    // -------------------------------------------------------------------------



    // -------------------------------------------------------------------------
    // Constructors :
    public DAO() { _connection = StaticPostgreSQLConnection.getInstance(); }
    public DAO(Connection connection) { _connection = connection; }
    // -------------------------------------------------------------------------
}

这是StaticPostgreSQLConnection:

public class StaticPostgreSQLConnection {


    // -------------------------------------------------------------------------
    private static final String _driverName = "org.postgresql.Driver";
    private static final String _url = "jdbc:postgresql://localhost:5432/telesciences";
    private static final String _user = "mylogin";
    private static final String _password = "mypassword";
    private static Connection _connection;
    // -------------------------------------------------------------------------



    // -------------------------------------------------------------------------
    public static Connection getInstance() {

        if (_connection == null) {
            try {
                Class.forName(_driverName);
                _connection = DriverManager.getConnection(_url, _user, _password);
            }
            catch (ClassNotFoundException | SQLException e) { e.printStackTrace(System.err); }
        }
        return _connection;
    }
    // -------------------------------------------------------------------------



    // -------------------------------------------------------------------------
    public static void close() {

        try {
            _connection.close();
            _connection = null;
        }
        catch (SQLException e) { e.printStackTrace(System.err); }
    }
    // -------------------------------------------------------------------------



    // -------------------------------------------------------------------------
    public static void begin() throws SQLException { getInstance().createStatement().execute("BEGIN;"); }
    public static void commit() throws SQLException { getInstance().createStatement().execute("COMMIT;"); }
    public static void rollback() throws SQLException { getInstance().createStatement().execute("ROLLBACK;"); }
    // -------------------------------------------------------------------------
}

编辑2:

这是一段postgres日志:

2014-02-12 11:02:02 CET LOG:  durée : 0.122 ms, analyse <unnamed> : select * from NAVIGATION_MESSAGE where date >= $1 order by date limit 1
2014-02-12 11:02:02 CET LOG:  durée : 0.143 ms, lien <unnamed> : select * from NAVIGATION_MESSAGE where date >= $1 order by date limit 1
2014-02-12 11:02:02 CET DÉTAIL:  paramètres : $1 = '2011-07-02 01:08:05.16'
2014-02-12 11:02:02 CET LOG:  exécute <unnamed>: select * from NAVIGATION_MESSAGE where date >= $1 order by date limit 1
2014-02-12 11:02:02 CET DÉTAIL:  paramètres : $1 = '2011-07-02 01:08:05.16'
2014-02-12 11:02:02 CET LOG:  durée : 157.295 ms

2014-02-12 11:02:02 CET LOG:  durée : 0.114 ms, analyse <unnamed> : select * from NAVSENSORS_MESSAGE where date >= $1 order by date limit 1
2014-02-12 11:02:02 CET LOG:  durée : 0.161 ms, lien <unnamed> : select * from NAVSENSORS_MESSAGE where date >= $1 order by date limit 1
2014-02-12 11:02:02 CET DÉTAIL:  paramètres : $1 = '2011-07-02 01:08:04.88'
2014-02-12 11:02:02 CET LOG:  exécute <unnamed>: select * from NAVSENSORS_MESSAGE where date >= $1 order by date limit 1
2014-02-12 11:02:02 CET DÉTAIL:  paramètres : $1 = '2011-07-02 01:08:04.88'
2014-02-12 11:02:02 CET LOG:  durée : 157.598 ms

每个请求只需要150毫秒,所以问题不在于postgres本身。我猜它来自我得到联系的方式。

1 个答案:

答案 0 :(得分:2)

解决了! 我做了两件事:

  • 我使用Tomcat的DataSource改变了获取连接的方式。这使我能够在300ms内执行每个请求(因此,在执行连续请求时不再有延迟)

  • 我在表格的日期字段上创建了一个索引,将每个请求的持续时间从150毫秒减少到...... 0-2毫秒!