2014-02-11 4 views
1

(J2EE 응용 프로그램에서) PostgreSQL 데이터베이스와 JDBC 드라이버에서 이상한 동작이 발생합니다. 그들 각자는 주어진 날짜에 emited 된 메시지가 포함J2EE - PostgreSQL - JDBC - 느린 쿼리

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

:

이의 내가 두 개의 테이블이 있다고 가정 해 보자, 간단하게합니다. 이제는 웹 사이트에서 이러한 정보를 재생해야합니다.

나는 AJAX를 사용하여 300-500ms마다 정보를 요청하고 있습니다. 요청은 다음과 같습니다. SHIP_MESSAGE에서 id, datetime, latitude, longitude를 선택하십시오. 여기서 date> = '2013-02-11 18:00:00'order by date limit 1;

한 번 실행하면 (첫 번째 테이블에서 메시지를 가져 오기 위해) 약 150ms가 걸립니다. 그러나 두 번 (두 테이블에서 메시지를 가져 오기 위해) 두 번 실행하면 각 쿼리에 800 ~ 2000ms가 걸립니다!

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 :

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의 구현 방법 특히 연결을 가져 오는 방법을 보여줄 수 있습니까? –

+0

상세한 PostgreSQL 쿼리 로깅을 가능하게합니다 - 적어도'log_statement = 'all''과'log_min_duration_statement = 0'. 그런 다음 PostgreSQL이 PostgreSQL 로그에서 명령문이 실행되는 데 걸린 시간을보고합니다. 이렇게하면 지연이 어디에서 발생하는지 파악하는 데 도움이됩니다. 또한'auto_explain'을 활성화하고 JDBC에서 실행할 때 생성 된 계획과 수동으로 실행할 때 생성 된 계획을 비교해보십시오. –

+0

기본 사항을 포함하는 것을 잊었습니다. 정확한 * PgJDBC 버전과 정확한 * PostgreSQL 버전 ('select version()')을 보여주십시오. –

답변

2

해결! 나는 두 가지 않았다 : 나는 Tomcat의 데이터 소스를 사용하여, 내 연결을 얻을 수있는 방법을 변경

  • 합니다.각 요청을 300ms에서 실행할 수있게되었습니다. (연속 요청을 할 때 더 이상 지연되지 않습니다.)

  • 각 요청 지속 시간을 150ms에서 150ms로 줄인 테이블의 날짜 필드에 인덱스를 생성했습니다. 2ms!