我遇到了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本身。我猜它来自我得到联系的方式。
答案 0 :(得分:2)
解决了! 我做了两件事:
我使用Tomcat的DataSource改变了获取连接的方式。这使我能够在300ms内执行每个请求(因此,在执行连续请求时不再有延迟)
我在表格的日期字段上创建了一个索引,将每个请求的持续时间从150毫秒减少到...... 0-2毫秒!