BLOG ARTICLE JDBC | 3 ARTICLE FOUND

  1. 2008/03/26 MySQL 관련
  2. 2008/03/21 Java JDBC Performance Tip(2)-Insert, Delete Speed up!
  3. 2008/03/21 JDBC Performance Tip - Select Speed Up. (1)

사용자 삽입 이미지
---------------------------------------
4. MySql은 어떻게 실행시키나요?
---------------------------------------
시작은 mysql설치 디렉토리 아래bin에(C:\mysql\bin) 가서  mysqld.exe 를 실행.
dos창이 잠시 보였다가 없어짐.
( 놀라지마세요. CTRL-ALT-DEL을눌러보면
mysqld-opt.exe(win95/98)나 mysqld-nt.exe(winnt/2000)가 실행중 )

확인법:
prompt> cd c:\mysql\bin
prompt> mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2 to server version: 3.23.21-beta

Type 'help' for help.

mysql>

c:\mysql\bin\mysql.exe는 mysql용 client program
이러한 메세지가 뜨면 정상적으로 MySql서버가 동작중임.
그리고 간단한 명령어 몇개를 입력해보죠.

mysql> show databases;      --> 기본적으로 만들어져있는 database 이름 출력
+----------+
| Database |
+----------+
| mysql    |
| test     |
+----------+
2 rows in set (0.00 sec)

mysql> select user();       --> 로긴한 사용자 정보 출력
+----------------+
| user()         |
+----------------+
| ODBC@localhost |
+----------------+
1 row in set (0.08 sec)

mysql>


위와같이 나오면 정상적인 설치임.
끝내려면 exit이라하면 됨.

mysql> exit;

---------------------------------------
5. Winnt/Win2000에서 서비스로 동작 시킬 수 있나요?
---------------------------------------

winnt/win2000에서는 mysql을 서비스로 등록가능.
방법 1 (command line ):  mysql설치 디렉토리 아래bin에 가면 mysqld.exe있음.

prompt> mysqld     -install  ( service로 등록 )
prompt> net start mysql   ( mysql 서비스 시작 )


prompt> net stop mysql ( mysql 서비스 중지 )
prompt> mysqld     -remove ( service에서 등록 해제 )

방법 2 (GUI) : c:\mysql\bin\win,ysqladmin.exe를 실행시킴.
그러면 userid와 암호를 묻는 화면이 뜰때 userid는 root, 암호는 sunedu21을 입력.
입력한 root는 기본적으로 제공되는 관리자용 id이고 암호는 없음. sunedu21을 입력하면
그걸로 자동 설정됨.

---------------------------------------
6. mysql.exe의 간단한 사용법을...
---------------------------------------

mysql.exe를 이용해서 다른 시스템의 database로 접속가능하고 다른 사용자로도 접속이
가능합니다.

mysql.exe옵션들

prompt> mysql [-h hostname] [-u userID] [-p암호] [database]

예:
prompt> mysql -h 203.239.XXX.XXX -u root -p sl300

-h 203.239.XXX.XXX  : 203.239.XXX.XXX으로 접속, 생략하면 기본값 127.0.0.1 이 사용됨.
-u root          : root사용자로 접속 -u옵션을 안주면 anonymous로 접속
-p               : 암호를 입력한후 접속. 암호를 묻는 프롬프트가 뜸.
                   암호가 있는 사용자로 접속시에는 반드시 사용.
                   만약 암호를 같이 입력하려면 암호를 -p옵션과 붙여 입력.(-ptiger)
database         : 사용할 database이름. 만약 생략하면 접속후 use명령으로
                   database를 지정해야됨. 기본제공 database name은 mysql,test 2개.ㄴ

---------------------------------------
7. MySql관련 GUI tool은 없나요?
---------------------------------------
MySql용 GUI tool은 대부분이 UNIX/LINUX용입니다.
다행히 3.23.21버전부터는 winmysqladmin.exe 라는 GUI tool이 포함되어 있읍니다.
( C:\mysql\bin\winmysqladmin.exe )
이 툴은 MySql서버를 start,stop시킬 수 있고, NT/2000에서는 service에 등록,해제도 가능합니다.
그리고 현재 접속하고있는 process의 갯수와 MySql관련 환경변수 정보와 설정정보까지
파악이 가능합니다.

이 툴은 win95/98/nt/2000에서 모두 동작합니다.
이명령어를 처음 실행하면 접속시 사용할 사용자id와 암호를 넣으라하는데 주로 root를 입력하고
암호는 아무거나 입력하면됩니다.
단 이때 입력한 암호는 자동으로 root의 암호로 인식이 됩니다. 반드시 기억해야겠죠?

그러면 시스템트레이에 신호등 아이콘이 생깁니다. 이걸 누르면 showme 와
winnt,win9X메뉴가 보이죠. winnt,win9X 메뉴를 선택하면 server start,stop tool의 shutdown이 보입니다.

현재 mysql server가 실행중이면 파란색불이 실행하지 않으면 빨간색 불이 들어옵니다.

만약 빨간색불(mysql서버가 중지중)일때 실행 시키려면 트레이에 있는 신호등 아이콘을 누르고
WinNT나Win9X를 선택, start the service 를 선택하면 신호등에 파라생 불이 들어옴.
즉 mysql서버가 시작했다는 말.

그외 관리용 명령어인 mysqladmin이 있음.
수동으로 실행시에는 mysqld.exe를 실행하면 되지만 수동으로 stop시키려면 mysqladmin을 실행.
물론 옵션과함께...
아래는 mysqladmin용 명령어임. 기능은 설명을 참조.

  create databasename   Create a new database
  drop databasename     Delete a database and all its tables
  extended-status       Gives an extended status message from the server
  flush-hosts           Flush all cached hosts
  flush-logs            Flush all logs
  flush-status          Clear status variables
  flush-tables          Flush all tables
  flush-threads         Flush the thread cache
  flush-privileges      Reload grant tables (same as reload)
  kill id,id,...        Kill mysql threads
  password new-password Change old password to new-password
  ping                  Check if mysqld is alive
  processlist           Show list of active threads in server
  reload                Reload grant tables
  refresh               Flush all tables and close and open logfiles
  shutdown              Take server down
  status                Gives a short status message from the server
  variables             Prints variables available
  version               Get version info from server

위 명령어중 특히 신경쓸것은 password관련.

설치후 반드시 root(MySQL DB)의 암호를설정할것. 
안하면 불행한일(DB삭제)이 발생할 지도...  

# mysqladmin -u root password 새암호

필요한 TABLE을 만드는 순서:
1. Database만들기
2. MySQL용 사용자 만들기
3. Table만들기

- javabrain용 DB 만들기(2가지 방법)
1.UNIX shell상에서 만들기
# mysqladmin -u root -p create javabrain

2.DB에 login후 만들기
mySQL에서제공하는 명령어중 mysqladmin은 관리용
mysql은 client용 명령어.

# mysql -u root -p mysql
mysql> create database javabrain;

** mysql 명령어 요약
mysql [-h DB서버IP] [-u DB용사용자ID] [-p[암호]] [Database] [< sql-script파일 ]
-p 만 부여하면  암호는 물어봄. 암호까지 주려면 -p암호(-p와 암호를 붙여씀)


- 새사용자등록
먼저 MySQL에 root로 login
# mysql -u root -p mysql

mysql> grant SELECT,insert,update,delete,create,drop
> on javabrain.*
> to scott@'localhost'
> identified by 'tiger';
mysql> grant SELECT,insert,update,delete,create,drop
> on javabrain.*
> to scott@'%'
> identified by 'tiger';
mysql> flush privileges;

또는

mysql> grant all privileges
> on javabrain.* to scott@'%'
> identified by 'tiger';

mysql> grant all privileges
> on javabrain.* to scott@localhost
> identified by 'tiger';
mysql> flush privileges;

scott 사용자를 등록할때 여러가지(3가지) 방법이 있는데 그중 하나를 씀
등록시 반드시 to scott@'localhost'와 to scott@'%'를 둘다 해줘야함
localhost와 %는 접속을 허용하는 hostname인데 localhost를 빼면 다른 시스템에서
network으로만 접근할 수 밖에 없음.
그리고 %란 모든호스트를 의미하기때문에 %를 지정해야지만 다른 시스템에서
network으로 MySQL로 접근가능( mysql -h hostIP또는hostname -u 사용자ID -p )

user생성후 반드시 DB를 reload 해야만 만든 사용자가 접속가능(아래명령어)

# mysqladmin -u root -p reload
또는
mysql> flush privileges;


접속해서 확인하기
# mysql -u scott -p javabrain  --> ㅤDB서버에서login

다른시스템에서
# mysql -h DB서버의IP주소 -u scott -p javabrain


필요한 테이블 만들기(customer,shares,stock)
-주의사항: mysql은 table name에서의 대소문자를 구분함
(이것은 MySQL이 설치된 OS를 따름. 즉 M$계열에서는 구분안함)

필요한 sql문을 파일(maketable.sql-확장자는 무관)로 만든후 shell상에서 아래
명령어 실행

# mysql -u scott -p javabrain < maketable.sql

확인
# mysql -u scott -p javabrain
mysql> show tables;
mysql> select * from customer;
mysql> select * from shares;
mysql> select * from stock;

- JDBC Driver 사용하기
MySQL용 JDBC Driver는 2가지가 있지만 여기서는 mm driver를 사용.

http://www.worldserver.com/mm.mysql/ 에 가서 최신 버전을 download할것
(mm.mysql-2.0.4-bin.jar)

가져온것을 적당한 곳에서 해제.

사용법:

Class.forName("org.gjt.mm.mysql.Driver");
String url="jdbc:mysql://127.0.0.1:3306/javabrain";
Connection conn = DriverManager.getConnection(url,"scott","tiger");



관련 명령어들.

# mysql -u root -p mysql
password:
mysql> select user();               --> 현재 어떤 user권한으로 접속하고 있는지.
mysql> show database;               -->데이터베이스 종류보기
mysql> show tables from mysql;      --> mysql상의 테이블 정보보기
mysql> show columns from customer;  --> customer 테이블 구조보기
mysql> show index from customer;    --> customer테이블의 인덱스보기
mysql> use mysql;                   --> 사용할 database를 변경
(기본적으로 MySQL에는 두개의 database-mysql,test-가 있음.
  mysql은 DBMS관리용 정보, test는 연습용
  그래서 mysql이란 database는 사용시 주의할것)


#########################################
#########################################
##
##   추 가 사 항
##
#########################################
#########################################

javabrain.sql 이라는 파일을 수행 시키면 SL-300을위한 DB를 위한 모든 내용이 자동 설정됨.

사용예)

mysql 서버를 가동시킨후 ( mysqld.exe )
prompt> mysql -u root -p <  javabrain.sql

이러면 아래 사항이 자동 생성됨
database이름  : javabrain
root암호   : javabrain
사용자 id  : scott
암호    : tiger
생성된table들  : customer, shares, stock

가끔씩 user부분이 적용이 안되는 경우에는 DB를 restart시키면 된다.

prompt> mysqladmin -u root -p shutdown   --> DB shutdown
prompt> mysqld

만약 암호를 바꾸고 싶으면  sql script내부에  .... identified by 다음부분이 암호이니
알아서 바꾸면 됨.  단 반드시 암호는 single quotation으로 묶어줄것.

예) 암호를 apple 로 하자면  .... identified by 'apple'


import java.sql.*;

public class MySQLJdbcTest {
   public static void main(String[] args) throws Exception{
      try{
        Class.forName("org.gjt.mm.mysql.Driver").newInstance();
        System.out.println("DriverLoading succeed..");

        String url="jdbc:mysql://127.0.0.1:3306/javabrain";
     //  만약 위의 url로 접속시 한글에 문제가 발생하면 아래 url을 써서 사용하도록 한다.

   //  String url="jdbc:mysql://127.0.0.1:3306/javabrain?useUnicode=true&characterEncoding=euc-kr";
        Connection conn =  DriverManager.getConnection(url,"scott","tiger");
        System.out.println("Connection succeed");
        Statement stmt = conn.createStatement();
        System.out.println("정보추출");
 
        ResultSet rs = stmt.executeQuery("show databases");
       while( rs.next() ) {
         System.out.println(rs.getString(1));
       }
       System.out.println("MySQL 환경 점검 종료");
       rs.close();
       stmt.close();
       conn.close();
      }catch(Exception e){
         System.out.println(e);
      }
    }
}

2003년 3월 작성.
크리에이티브 커먼즈 라이센스
Creative Commons License
2008/03/26 14:23 2008/03/26 14:23

사용자 삽입 이미지
이것도 2001년에 썼던 글입니다.

이전 아티클에서는 database select speedup에 대하여 알아보았다. 이번 편에서는 update를 제외한 insert, delete tranaction의 속도를 최대로 끌어올릴 수 있는 방안을 살펴보자.

▶ Insert, Delete Query speed up!

JDBC 2.0에서는 기본적으로 scrollable한 메소드등의 유연성있는 메소드들과  batch processing에 관련된 메소드가 추가되었다.

그게 바로 어떤 것이냐하면 Statement, PreparedStatement 인터페이스의 addBatch(String sql),
addBatch()메소드이다. Pro*C같은 경우 기본적으로 array processing을 이용하여 데이터베이스에 작업을 하므로 상당한 퍼포먼스를 낼 수 있는데 이를 자바측으로 변환한것이 바로 addBatch메소드인 것이다.

첨보았는가? 아니면 아래의 BMT아티클에서도 보았는가?
Other--> Development를 보게 되면 Java vs Pro*C의 비교자료가 있다. 한번읽어보기 바라며 그 내용의 상세부분을 간략한 코딩으로서 당신에게 보여주고자 한다.

기본적으로 java에서도 그러한 배치기능을 사용하고자 한다고 하고, 당신이 만약 드라이버 개발자라고 하면 어떻게 데이터베이스에 작업을 할것인가?

그나마 setAutoCommit(false)를 connection에 때려넣어놓으면 commit에 대한 그만큼의 비용이 떨어질것이라는걸 알고 있다면 다행이겠다. 자. 그러면 데이터를 소위 "밀어넣는다"라고 이야기했을 때 가장 최선책은? 건당 하는 건 무리일테고, 음~ 자바니까 Collection을 이용해보면 딱이겠다.

그리고 Collection을 이용한다면 들어오는 데이터는 중복을 허용하고 순서도 있어야 할테니까
List 계열을 사용하는 것을 좋겠고.. 놀새의 결론은 List중에서도 제일 퍼포먼스가 좋은 ArrayList를 사용하는게 딱일것이라고 생각했다. 하지만 실제 Driver는 어떠한 자바버젼에서도 맞아야 하기 때문에 1.2부터 사용되는 ArrayList는 좀 고려해 볼만도 하다.

그러면 뭐가 들어오는 sql문장에 대한 저장소로 적당할 것인가? 답은 Vector!! 왜 Vector인지는 설명하지 않겠다. 이정도 글읽는 당신정도라면 API는 어느정도 숙지하고 있을 거라는 놀새의 생각때문이다.

우선 그러면 실제 Oracle을 예로 driver내부나 한번 보도록 할까?

JDBC API Statement 인터페이스의 구현체인 OracleStatement코드의 addBatch메소드를 잠깐보자


    public synchronized void addBatch(String s)
        throws SQLException
    {
        addBatchItem(s);
    }

    private void addBatchItem(String s)
    {
        m_batchItems.addElement(s);
    }
 

어라? addElement를 사용하는 걸 보니 놀새가 생각했던 것처럼 Vector를 사용하고 있다. 즉 batch를 위한 저장소로서 Vector class를 사용중인 것이다. 그러면 Statement클래스의 실제 batch execute 명령어인 executeBatch()메소드를 보도록 하자.

   

public int[] executeBatch()
        throws SQLException
    {
        synchronized(connection)
        {
            synchronized(this)
            {
                int i = 0;
                int j = getBatchSize();
                if(j <= 0)
                {
                    int ai[] = new int[0];
                    return ai;
                }
                int ai2[] = new int[j];
                Object obj = null;
                Object obj1 = null;
                Object obj2 = null;
                boolean flag = false;
                ensureOpen();
                prepare_for_new_result(true);
                try
                {
                    connection.needLine();
                    for(i = 0; i < j; i++)
                    {
                        String s = getBatchItem(i);
                        String s1 = expandSqlEscapes(s);
                        byte abyte0[] = strToDbaccessBytes(s1);
                        byte byte0 = getSqlKind(s1);
                        if(byte0 == 0)
                            DBError.throwBatchUpdateException(80, "invalid SELECT batch command " + i, i, ai2);
                        ai2[i] = parseExecuteFetchWithTimeout(dbstmt, byte0, abyte0, null, 1, null, 1);
                        if(ai2[i] < 0)
                            DBError.throwBatchUpdateException(81, "command return value " + ai2[i], i, ai2);
                    }

                }
                catch(IOException ioexception)
                {
                    DBError.throwBatchUpdateException(81, ioexception.getMessage(), i, ai2);
                }
                catch(SQLException sqlexception)
                {
                    if(sqlexception instanceof BatchUpdateException)
                        throw sqlexception;
                    DBError.throwBatchUpdateException(81, sqlexception.getMessage(), i, ai2);
                }
                finally
                {
                    clearBatchItems();
                }
                int ai1[] = ai2;
                return ai1;
            }
        }
    }

위에서 보면 당연히 connection은 동기화되어져야 하므로 synch걸어놓고 작업할게 뻔하며,
parseExecuteFetchWithTimeout메소드가 실제 update작업을 이루게끔 하는데 저놈은 timeout이
걸려있으면 타이머 작동시키고 statement에 update때리는 작업을 하며, timeout이 0이면 바로 update이다. 복잡한가?

PreparedStatement(이하 PS)의 addBatch()메소드는 조금 더 복잡하므로 간략하게 어떻게
작동되는지만 설명하겠다. PS의 경우는 쿼리가 이미 database의 내부 procedure로 변환되어져 있기 때문에 Stream을 이용하여 데이터를 세팅시키는 일을 한다는 것이 Statement Batch와 틀린 점이다. 그렇다면 Statement와 PreparedStatement의 속도차이는 얼마나 될까? 놀새는 이미 전부 다 해봤기 때문에 이건 당신의 숙제로 남겨두겠다.

위의 내용복잡하면 몰라도 됨을 강력히 주장한다. 당신이 JDBC Driver개발자가 아니지 않은가~!! ^^

자 그럼 이제 코더의 신분으로 돌아왔다고 가정을 하고, API를 이용하여 코딩이나 한번 해보자.

단순히 API를 사용하는 것이므로 거창하게 설명하고 자시고 할 필요도 없이 바로 들어간다.
알아서 보라~


 

public class BatchTest {
    private Connection getConnection(){
        // 알아서 연결들 하라~! ^^
    }
   
    private void close() {
        // 알아서 연결을 닫아라
    }

    public void insertABT231Batch(){
        System.out.println(Utility.getTime()
        + " Insert ABT231 Batch Start .. Transaction size is " + m_abt231InsertList.size());
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            StringBuffer query = new StringBuffer();
            query.append("INSERT INTO ABT231 ");
            query.append("(customer_no, item_cd, occur_amt, reason_cd, register_ymd, register_no) ");
            query.append(" VALUES (?, ?, ?, '9', ?, ?) ");

            conn = getConnection();
            conn.setAutoCommit(false);

            pstmt = conn.prepareStatement(query.toString());
            Iterator iter = m_abt231InsertList.iterator();
            int count = 0;

            while( iter.hasNext() ) {
                m_abt231 = (Abt231) iter.next();
                pstmt.setInt(1, m_abt231.getCustomerNo());
                pstmt.setString(2, m_abt231.getItemCd());
                pstmt.setLong(3, m_abt231.getOccurAmt());
                pstmt.setString(4, s_magamCurrentTime);
                pstmt.setInt(5, Integer.parseInt(s_workCd));
                pstmt.addBatch();
                count++;
                if( (count % 10000) == 0){
                    System.out.println(count + "건 처리중");
                    pstmt.executeBatch();
                }
            }

            pstmt.executeBatch();
            conn.commit();
            System.out.println(Utility.getTime() + "] " + count + "건 입력완료");
        } catch ( Exception e) {
            e.printStackTrace();
            try{
                conn.rollback();
            }catch(Exception e2) {e2.printStackTrace();}
        } finally {
            close(pstmt);
            close(conn);
        }
    }
}
 

위에서 유심히 볼거라고는 bold체로 쓰여진 부분의 내용뿐이다. 위의 내용은 데이터베이스에서
추출된 데이터를 다시 계산하여 다른 데이터베이스 테이블에 insert하는 내용이며, ArrayList에 담긴 대량의 데이터를 iteration하며 batch를 실행하는 것이다.

좀 더 자세한 메소드 설명은 API의 내용을 참조해도 무방할 듯 싶다.

addBatch()처음보는가? 그러면 다른 클래스를 예로 들어서 java.lang패키지 클래스의 메소드는
자유자재로 구사할 줄 아는가?

놀새가 아는 사람들끼리의 고수에 대한 표현은 다음과 같다.

"저 사람은 걸어다니는 API야~!"

아무렇지도 않은 것 같으면서도 얼마나 함축적인 표현인가~!! ( 나만 그런가? ㅎㅎ)
API를 이용하여 쉽게 만들수 있는데도 예전 C코딩처럼 함수 열나 만들어서 잘 만들었다고 자랑해봤자 위의 걸어다는 API한테 망신당할 수 있다는 걸 명심해야 한다.

중요하게 쓰일수 있는 것은 바로 옆에 있으며, 당신눈에 띄지 않는 것이 대부분이다.
두 눈 크게 뜨고 다녀야 한다. API가 바로 그것인 것이다.
--------------------------------------------------------------------------------
아참. 그리고 위의 코드같은거 테스트할 때 웬만하면 TestCase만들어서 작성하세요. 습관이 중요합니다. 단위테스트의 중요성은 나중에 칼럼 쓸 일 있으면 쓰도록 하겠습니다.

크리에이티브 커먼즈 라이센스
Creative Commons License
2008/03/21 13:58 2008/03/21 13:58

사용자 삽입 이미지
2001년에 썼던 글입니다.

이번 아티클에서는 자바에서의 배치작업에 대하여 논하여 보자. 전부터 이부분에 대하여
작성을 한다고 직접 적어놓고서 이제야 만들어 내는 놀새의 게으름을 이해해주기 바란다.
왜냐~~ 요즘 너무 바쁘기 때문에.. ^^

이런거 이미 알고 있으면서도 혼자만의 기술인냥 숨기고 있는 사람들이 있을까봐 열심히 만들어서 아티클로 쓴다. 혼자 알고 있으면 뭐하리요. 인터넷은 헛빵으로 있는 것이 아니다. 정보의 바다인 것이다.

지금 시간이 없다.. 바로 시작한다. 

일전 방명록에 이런 작업을 하는 분의 문의가 있었다. 요약하면 다음과 같은데 "당신의 연구성과를 잘 보고 있다, 우리 사이트는 배치작업을 Pro*C로 하고 front-end단은 자바로 한다. 하고 싶은
말인즉은 배치도 자바로 짜고 싶다. 퍼포먼스를 나게 하는 방법을 알려달라" 라는 것이 요지였다.

작년말의 프로젝트에서도 배치를 하긴 했지만 그때는 java data를 읽어내어 Visual Basic에서 처리하는 배치프로그램이어서 자바보다는 VB에 가까운 형태였고, 고생도 많이 했다.

하지만 이번에는 순수 자바배치를 이용하도록 한다. 당연히 transtion상황하이므로 insert, update, delete에 관한 것임을 염두에 두어야 한다.

우선 워밍업으로 select를 빨리 해올 수 있는 방법을 잠깐 보도록 하자.

단~ 우선 알아두어야 할 것은 이번 아티클은 오라클을 이용한 샘플임을 알아두도록 하자.

▶ Select Query speed up!

Database record select속도를 높일 수 있다?  흠.
오라클 데이터베이스의 메모리 구조에서 사용하는 영역을 Oracle JDBC까지 연결시켜 보면 쉽게 보이는 것이다. 보통 오라클같은 경우 Software Code Areas, P.G.A (Program Global Area),
S.G.A (System Global Area) 로 나눌수 있다

간략하게 나마 설명을 해보자면

1) SoftWare Code Areas.
 오라클의 실행 모듈들이 메모리에 할당되는 공간이다.
 일반 유저 프로그램이 접근할 수 없고, 크기는  O/S 에 따라 약간씩 다르지만 Virtual Memory 에 위 치하게 된다.

2) S.G.A ( System Global Area )
 오라클 인스턴스의 한 부분으로 인스턴스가 기동 (Startup) 할때 메모리에 잡히게 되는 작업 영역이다.  이 영역은 오라클이 기동중에 사용되는 데이타나 각종 정보들, 그리고 일반 유저들의 모든 SQL 문장들을 이곳에서 수행한다.  주로, Real Memory 에 위치하게 된다.

3) P.G.A ( Program Global Areas )
 유저가 요청한  SQL 문장을 처리하기 위해서 각 세션마다 선언된 변수 값들을 임시로 저장하는 영역으로, DisConnect 하면, 자동으로 Release 된다

자, 그러면 우리가 사용하는 JDBC의 연결영역은 어떻게 될것인가?

위의 설명에서 처럼 SGA를 사용할 것 같다. SGA는 Data Buffer Cache를 가지고 있게 되는 데 이것은 SQL 문장을 실행할때 필요한 데이타를 디스크에서 SGA 영역으로 읽어 들이는 곳이다.
여기에는 변경된 데이터뿐만 아니라 변경되지 않는 데이터도 가지고 있는데, 이는 수행속도 향상을 위해 디스크 입출력 보다는 메모리 Access를 하게 하기 위함이다.
이 영역이 크면 그만큼 많은 데이타를 SGA 영역에 올려놓을 수 있으므로 메모리에서 바로 읽을 수 있는 Hit 율이 높아진다. 그러나, 이 영역이 너무 작으면 스와핑(Swapping) 이 많이 발생되므로 시스템의 성능에 영향을 준다. 조회 속도를 높이기 위해선 이 영역을 충분히 크게 해야 하는데
이곳을 걸고 넘어질 수 있는 Java API가 ResultSet 클래스의 setFetchSize(int rows) 메소드이다. 즉 JDBC Driver가 ResultSet을 통해서 가져올 데이터의 fetch크기를 결정하게 하는 것이다.

퍼포먼스에서 항상 나오는 이야기이지만 이러한 값들은 너무 커도 안되고 너무 작아도 안된다는것이다.
데이터베이스마다 최적의 성능을 나타내는 값으로 세팅되어져야 함은 물론이다.
또한 0 <= rows <= Statement.getMaxRows() 임은 당연하겠다.

적은 양의 데이터베이스의 select 쿼리시에 위의 fetch size에 대한 결정은 별 차이점을 드러내지 않지만 대량의 데이터를 조회하는 ResultSet의  경우 그 차이는 점점 극명하게 나타나는 것을 확인할 수 있다.

간단한 예제를 보겠다.
이 예제에서 사용되는 abt140이란 테이블은 현재 6,511,102건의 데이터를 가지고 있다.
fetch size를 지정하고 안하고 의 경우를 통하여 결과값을 보도록 하겠다.

import java.sql.*;
import java.io.*;

class FetchSizeTest {
    public static void main(String[] args) throws Exception {
        Class.forName("oracle.jdbc.driver.OracleDriver");
        String url ="jdbc:oracle:thin:@192.168.0.137:1521:abn";
        Connection conn = DriverManager.getConnection(url,"abs","abs");
        String query = " select * from abt140";
        PreparedStatement stmt = conn.prepareStatement(query);
        long start = System.currentTimeMillis();
        ResultSet rs = stmt.executeQuery();
        rs.setFetchSize(10000);
        while(rs.next()) {
            new String("xx");
        }
        System.out.println("Time elapsed : " + (System.currentTimeMillis() - start));
        rs.close();
        stmt.close();
        conn.close();
    }
}
 

위 프로그램에서 setFetchSize를 적용시키기 전과 후의 결과값은 다음과 같다.

Fetch Size 적용안할 경우 : Time elapsed --> 423038
Fetch Size를 10000 rows로 적용할 경우 : Time elapsed --> 101556

위의 경우 속도차이가 거의 4배가 나는 것을 볼 수 있으며, 꼭 10000개의 record를 fetch로 하는게 최상의 퍼포먼스가 아님을 명심해두자.

크리에이티브 커먼즈 라이센스
Creative Commons License
2008/03/21 13:52 2008/03/21 13:52