2014-02-11 95 views
1

我遇到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自身內部。我想這是來自我獲得聯繫的方式。

+0

可以顯示MessageDao get方法的實現,特別是獲取連接嗎? –

+0

啓用詳細的PostgreSQL查詢日誌記錄 - 至少log_statement ='all''和'log_min_duration_statement = 0'。然後報告PostgreSQL說這些語句在PostgreSQL日誌中運行的時間。這將幫助你隔離延遲的地方。另外考慮啓用'auto_explain'並將從JDBC運行時生成的計劃與手動運行時生成的計劃進行比較。 –

+0

您忘記了包含基礎知識。請顯示*精確* PgJDBC版本和精確* PostgreSQL版本('select version()')。 –

回答

2

解決! 我做了兩兩件事:

  • 我改變讓我的聯繫方式,使用Tomcat的數據源。這使我可以在300ms內執行每個請求(因此,在連續請求時不會再有延遲)

  • 我在我的表的日期字段上創建了一個索引,它將每個請求持續時間從150ms減少到... 0- 2ms!