我遇到PostgreSQL數據庫和JDBC驅動程序(在J2EE應用程序中)的奇怪行爲。J2EE - PostgreSQL - JDBC - 緩慢查詢
爲了簡單起見,假設我有兩個表:
SHIP_MESSAGE(id, datetime, latitude, longitude)
SUBMARINE_MESSAGE(id, datetime, latitude, longitude, immersion)
它們中的每一個包含已經在給定的日期時間被emited消息。現在我必須在網站上重放這些信息。
我使用AJAX來請求每300-500ms周圍的信息。請求類似於: 從SHIP_MESSAGE選擇ID,日期時間,經度,經度,其中date> ='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自身內部。我想這是來自我獲得聯繫的方式。
可以顯示MessageDao get方法的實現,特別是獲取連接嗎? –
啓用詳細的PostgreSQL查詢日誌記錄 - 至少log_statement ='all''和'log_min_duration_statement = 0'。然後報告PostgreSQL說這些語句在PostgreSQL日誌中運行的時間。這將幫助你隔離延遲的地方。另外考慮啓用'auto_explain'並將從JDBC運行時生成的計劃與手動運行時生成的計劃進行比較。 –
您忘記了包含基礎知識。請顯示*精確* PgJDBC版本和精確* PostgreSQL版本('select version()')。 –