블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 



구글 빅데이타 플랫폼 빅쿼리 소개


조대협 (http://bcho.tistory.com)


구글의 클라우드 관련 기술중 무엇이 좋은게 있을까 살펴 보면서 기술을 하나하나씩 보다 보니, 구글 클라우드의 특징은 여러가지가 있겠지만, 데이타 회사 답게 빅데이타 및 머신 러닝 플랫폼이 상당히 강하다.


그중에서 빅데이타 플랫폼의 중심에 BIG QUERY라는 빅데이타 플랫폼이 있어서, 몇 회에 걸쳐서 빅쿼리에 대해서 소개해보고자 한다.

구글 빅데이타 분석의 역사

구글은 빅데이타를 다루면서, 그 근간이 되는 기술들의 논문들을 공개했다. 하둡 파일 시스템의 시초가 되는 GFS나, 하둡의 시초인 MapReduce 논문, 그리고 Hive를 통해 오픈소스화가 된 Big Table등의 논문들이 있다. 구글의 빅쿼리는 Dremel 이라는 논문을 근간으로 한다.

빅쿼리랑 무엇인가?

빅쿼리는 페타 바이트급의 데이타 저장 및 분석용 클라우드 서비스이다.

요즘은 페타바이트급의 data warehouse로 부르는데, 쉽게 말해서 페타바이트급의 데이타를 저장해놓고, 쿼리를 통해서 조회나 통계 작업등을 할 수 있는 DB(라고 보기에는 약간 애매하지만)이다.

빅쿼리의 특징

대략적인 특징을 살펴보면 다음과 같다.

클라우드 서비스로 설치/운영이 필요 없음 (NoOps)

어디에 설치해서 사용하는 서비스가 아니라 구글 클라우드 서비스를 통해서 제공되는 빅데이타 저장 분석 서비스이다. 클릭 몇번으로 서비스 사용이 가능하고, 별도의 설정이나 운영이 필요 없다.

SQL 언어 사용

기존의 RDBMS에서 사용되는 SQL언어를 그대로 사용하기 때문에, 사용이 매우 쉽다.

클라우드 스케일의 인프라를 통한 대용량 지원과 빠른 성능

빅쿼리의 성능이나 스케일을 보려면 다음 예제를 보는게 좋다.

https://cloud.google.com/blog/big-data/2016/01/anatomy-of-a-bigquery-query


위키피디아에서 100 billion record (1000억개)의 레코드를 스캐닝해서 regular expression으로 “G.*o.*o.*g”) 문자열을 찾아내서 그 문서의 뷰수를 카운트 하는 예제이다.

대략 4TB 용량의 데이타가 핸들링 되고, 약 30초가 소요된다.

30초 동안, 약 3,300개의 CPU와, 330개의 하드 디스크, 330 Gigabit의 네트웍이 사용된다.

(자료 : https://cloud.google.com/blog/big-data/2016/01/bigquery-under-the-hood)

이 쿼리를 수행하는데 소요되는 비용은 딱 $20가 소요된다.

일반적인 인프라에서 빅데이타 연산을 하는데, 3300개의 CPU를 동시에 사용하기란 쉽지 않은 일이고, 이런 대용량 연산을 20$에 할 수 있는 것은 대용량 인프라를 공유하는 클라우드 서비스이기 때문에 가능하다.

데이타 복제를 통한 안정성

데이타는 3개의 복제본이 서로 다른 3개의 데이타 센터에 분산되어 저장되기 때문에 데이타에 대한 유실 위험이 적다.

배치와 스트리밍 모두 지원

한꺼번에 데이타를 로딩하는 배치 이외에도 REST API등을 통해서 실시간으로 데이타를 입력할 수 있는 스트리밍 기능을 제공하며, 스트리밍시에는 초당 100,000개의 행(row)의 데이타를 입력할 수 있다.

비용 정책

비용 정책 역시 클라우드 서비스 답게, DB 인스턴스와 같은 과금 방식이 아니라서 큰 데이타를 핸들링 하기 위해서 큰 인스턴스를 쓰고 사용하지 않는 동안에도 과금이 되는 정책이 아니라,

딱  저장되는 데이타 사이즈와, 쿼리시에 발생하는 트렌젝션 비용만큼만 과금이 된다.  데이타 저장 요금은 GB당 0.02$이고, 90일이 지나서 사용하지 않는 데이타는 자동으로 0.01$로 가격이 떨어진다.

클라우드 서비스에서 가격이 싸다는 일반적인 오브젝트 스토리지 (Google Cloud Storage : GB당 0.026$)보다 싸다. 트렌젝션 비용은 쿼리 수행시 스캔되는 데이타를 기준으로 TB당 $5 이다.  (월  1TB는 무료)
(나중에 자세하게 설명하겠지만, 스캔되는 컬럼당 비용이 나오기 때문에 사실상 비용을 계산해보면 그리 높지 않다)

가격 정책 : https://cloud.google.com/bigquery/pricing


빅쿼리가 기존의 빅데이타 플랫폼과 다른점은?

그렇다면 빅쿼리가 기존의 빅데이타 분석 플랫폼인 Hadoop, Spark등과의 차이가 무엇일까? 앞의 장점을 기반으로 그 차이점을 정리하자면 크게 다음과 같은 3가지를 들 수 있다.

쉽다.

보통 Hadoop이나 Spark등을 사용하게 되면, Map&Reduce(이하 MR) 로직을 사용하거나 SparkSQL을 사용하더라도 일정 수준 이상의 전문성이 필요하다. 또한 MR 로직의 경우 전문성이 있는 개발자가 분석 로직을 개발해야 하기 때문에 시간이 상대적으로 많이 소요되지만 빅쿼리는 로그인 후 SQL만 수행하면 되기 때문에, 상대적으로 빅데이타 분석이 쉽다.

운영이 필요 없다

Hadoop이나 Spark과 같은 빅데이타 솔루션의 경우에는 인스톨과 설정 그리고 클러스터의 유지 보수가 보통 일이 아니다. 그래서 별도의 운영 조직이 필요하고 여기에 많은 리소스가 소요되지만, 빅쿼리는 클라우드 서비스 이기 때문에, 별도의 운영등에 신경을 쓸 필요가 없이 개발과 분석에만 집중하면 된다.  

인프라에 대한 투자없이 막강한 컴퓨팅 자원을 활용

앞의 예에서 본것과 같이, 빅쿼리를 이용하면 수천개의 CPU와 수백/수천개의 컴퓨팅 자원을 사용할 수 있다. 물론 기존 빅데이타 플랫폼도 클라우드 환경에 올리면 수천개의 CPU를 사용하는 것이 가능은 하지만, 그 설정 작업과 비용적인 측면에서 차이가 크다.

빅쿼리 맛보기

그러면 직접 빅쿼리를 사용해보자. 빅쿼리 버전 HelloWorld라고 생각하면 된다.

가입 하기

http://cloud.google.com 으로 들어가서 구글 클라우드 서비스에 가입을 한후에,  로그인을 해서 아래 그림 처럼 결재 메뉴에서 빌링 정보를 입력한다 (신용 카드 정보 입력)



계정이 생성되면 자동으로 $300 의 무료 사용권이 생성되고, 이 금액은 60일동안 사용할 수 있다. (60일이 지나면 자동으로 소멸된다. ).

신용 카드 정보를 넣었더라도, 사용자가 직접 과금이 되는 플랜으로 업그레이드를 하지 않는 이상 과금이 되지 않으니 이 부분은 걱정하지 말기 바란다.

프로젝트 생성

구글 클라우드는 VM이나 각종 자원들을 프로젝트라는 개념으로 묶어서 사용한다. 처음 계정을 생성했으면 프로젝트가 없기 때문에 프로젝트를 생성하자.

아래 그림과 같이 상단 우측 메뉴에 프로젝트 생성 메뉴가 있다.


프로젝트 생성을 선택한 후 아래와 같이 프로젝트 이름을 입력하면 프로젝트가 생성된다.


빅쿼리 콘솔로 이동하기

프로젝트가 생성되었으면 메뉴에서 아래 그림과 같이 BigQuery 메뉴를 선택하게 되면 빅쿼리 웹 콘솔로 이동이 된다.




빅쿼리 메뉴로 들어가면 다음과 같은 작업 창이 나온다.




좌측은 프로젝트와 프로젝트에 속한 데이타셋과 테이블 리스트가 나온다.

나중에 데이타 모델을 다시 설명하겠지만, 데이타 셋 (dataset)은 RDBMS의 db와 같은 개념으로 테이블의 집합이라고 보면 되고, 그 안에 개별 테이블들이 들어가 있다.

우측 상단 쿼리 입력창에는 SQL을 입력해서 쿼리를 실행하고, 우측 아래에는 쿼리 결과를 볼 수 있다.

쿼리 실행

그러면 실제로 간단한 쿼리를 수행해보자

빅쿼리에서는 테스트를 위해서 몇가지 데이타 셋을 공개로 해놓았는데, bigquery-samples라는 데이타 셋에서 1000억개의 레코드를 가지고 있는  wikipedia_benchmark.Wiki100B 테이블에서, 위키 페이지 제목이 “Seoul”또는 “seoul”인 페이지의 제목과 뷰수를 쿼리를 해본다.


다음과 같이 쿼리를 입력하고


select title,sum(views) as views

from [bigquery-samples:wikipedia_benchmark.Wiki100B]

where regexp_match(title,'[Ss]eoul')

group by title

order by views desc;


쿼리 입력창 하단에 체크 마크를 누르면 다음과 같은 화면이 출력된다.


쿼리를 수행하기 전에, 쿼리가 제대로 되었는지 확인을 해주고, 위와 같이

Valid: This query will process 3.64 TB when run.”

3.64 TB를 스캐닝 할것임을 알려준다. (이를 통해서 쿼리 수행 비용을 예측해볼 수 있다.)


“Run Query” 버튼을 눌러서 쿼리를 수행하면 다음과 같은 결과를 얻을 수 있다.


RUN QUERY 버튼 가장 우측에 총 3.64TB를 처리했고, 총 수행 시간은 38.9초가 걸렸음을 확인할 수 있다.

그리고, 아래 쿼리 결과가 나온다.

Seoul 로 된 페이지가 11258720회 조회되었고, Seoul_National_University가 다음으로 894040회, FC_Seoul이 802570회 조회 된것을 확인할 수 있다.


지금까지 간략하게나마 빅쿼리에 대한 소개와 주요 특징 그리고 간단한 사용법을 소개했다.

다음 글에서는 빅쿼리의 내부 아키텍쳐에 대해서 설명하도록 한다.


RDBMS 프로그래밍시에는 해당 RDBMS에 대한 드라이버(모듈을) import해야 한다. sqlite의 경우는 이미 들어가 있다. 아래는 가장 기본적인 코드 이다.

import sqlite3


conn = sqlite3.connect("datafile")

cursor = conn.cursor()

cursor.execute("drop table test")

cursor.execute("create table test (name text,count integer)")

cursor.execute("insert into test(name,count) values('Terry',1)")

cursor.execute("insert into test(name,count) values('Cath',2)")

conn.commit()

result = cursor.execute("select * from test")

while True:

    row = result.fetchone()

    if row == None:

        break

    print row[0],row[1]

conn.close()

데이타 베이스 프로그래밍 순서

  1. 먼저 import를 통해서, 해당 데이타베이스를 접근하기 위한 모듈을 import한다.
  2. 해당 모듈.connect를 이용하여 데이타 베이스 connection을 연결한다. dbms에 따라서 connection string이 다르다. sqlite의 경우 파일 기반이기 때문에, 파일경로만 지정하면 되고, mysql의 경우에는 host,userid,userpasswd,dbms 식으로 기술해주면 된다.
  3. 다음은 cursor를 connection으로 부터 생성한다.
  4. cursor.execute를 통해서 query를 실행한다.
  5. select의 경우에는 result를 받은후에
    • - fetchall()의 경우 결과를 모두 리턴
    • - fetchone()의 경우 하나의 row를 리턴
    • - fetchmany(num rows)의 경우 rows의 숫자 만큼 리턴을 한다.
  6. conn.commit을 이용하여 transaction을 commit한다.
  7. 마지막으로 사용한 connection을 close한다.
mysql 데이타베이스도 다르지 않다. (정말 쉽다.)

다음은 약간 더 진보된 코드로, 데이타베이스에 대한 에러 핸들링을 포함하고 있다.

import sqlite3

try:
    conn = sqlite3.connect("datafile")
    cursor = conn.cursor()
    cursor.execute("drop table test")
    cursor.execute("create table test (name text,count integer)")
    cursor.execute("insert into test(name,count) values('Terry',1)")
    cursor.execute("insert into test(name,count) values('Cath',2)")
    conn.commit()
    result = cursor.execute("select * from test")
    while True:
        row = result.fetchone()
        if row == None:
            break
        print row[0],row[1]
except sqlite3.Error, e:
    if conn:
        conn.rollback
finally:
    if conn:
        conn.close()

기본적으로 sqlite 라이브러리가 포함되어 있는게 마음에 든다. 간단한 tutorial이나, 간단한 dbms 프로그래밍의 경우 별도의 라이브러리 설치가 필요없다.




List 데이타형 : []를 사용

lines = string.split(text,'\n') # text를 \n을 delimiter로 사용하여 한줄씩 나눠서 배열 형태로 리턴 

chunk = lines[:to] # chunk에 0~to까지 set을 리턴

chunk = lines[from:] # chunk에 from~끝까기 set을 리턴

chunk = lines[:] # []에 대한 전체 set을 리턴


K/V 형태의 Dictionay : {} 를 사용

terry = { 'name':'terry','age':39} # {}안에 'key':'value' 형식으로 데이타 저장

cath = { 'name':'cath','age':38}

print terry['name'] # 특정 필드에 대한 접근은 ['key']를 사용


List of dictionary

dictN = {'key':'value', ...}

lists = [dict1,dict2,....dictN}


SQL like query

[rec['name'] for rec in people if rec['age']>30]


Tuples

()로 표현되며, list와는 다르게 수정이 불가능함. 

- tuple to list : t = tuple([x1,2,3])

- list to tuple : l = list( (1,2,3,4))


pickle

list나, dictionary등의 python 데이타 타입을 serialize하여 파일에 저장

import pickle 後 사용

- 저장(serialize) pickle.({dataobject},fd)

- 읽기(deserialize) {dataobject}=pickle.load(fd)

- 확장자는 *.pkl로 하는게 좋음 (필수 아님)


※ 크롬에서 간단한 Python 프로그래밍 테스트 - Python Shell 플러그인 https://chrome.google.com/webstore/detail/python-shell/gdiimmpmdoofmahingpgabiikimjgcia


Azure Data Storage Service

요즘 어찌어찌 해서, 클라우드쪽과 특히 마이크로소프트의 클라우드 플랫폼인 Azure 쪽을 보고 있는데, 상당히 흥미롭다. 국내 기업을 대상으로 서비스를 제공하고 있지 않고 국내에 .NET 개발자층이 자바쪽에 비해서 두텁지 않은 관계로, 크게 이슈화는 못 되어가고 있는 것 같지만 기술적인 관점에서는 상당히 흥미롭다. Azure를 한마디로 이야기 하자면 넣을 수 있는 건 정말 다 넣었다. CRM,Exchange 등등과 같은 소프트웨어 서비스 기반의 Saas에서부터 Windows 기반의 Iaas 까지, 거기에 SNS 통합 인증, Windows Live Service등에서 제공되는 OPEN API Integration까지 참 많기는 많다.

하여간 자세한 이야기는 나중에 올리도록 하고, 오늘은 Azure Platform의 데이터 저장 서비스에 대해서 알아보고자 한다.

기업이 클라우드를 사용하려는 근본적인 이유와, 모든 클라우드 업체들이 내세우는 클라우드의 장점은 결국 비용이다. 쓴 만큼 지불하는 비용 구조를 제공하겠다는 것인데, 컴퓨팅에서 비용은 결국 컴퓨팅 파워 (CPU)와 저장소(Storage)비용이다. 그래서 클라우드 서비스들은 강력한 Storage 서비스등을 제공한다. Amazon도 SimpleDB,S3,EBS,RDS,SQS(엄밀하게는 Queue 서비스) 등의 다양한 서비스를 제공하고 있고, Microsoft의 Azure역시 다양한 형태의 Storage 서비스를 제공한다. 일반적으로 클라우드 상의 Storage 서비스는 RDBMS 처럼 OLTP를 지원하기 위한 고급 Feature들 보다는 대용량의 데이터를 저장할 수 있는 Scalability와 대용량 데이터를 Handling할 수 있는 Performance 에 초점이 맞춰져 있다.

일단 Microsoft의 Azure의 Storage 서비스를 보면 크게 아래와 같이 5가지 형태의 서비스를 제공한다.


Table Storage
말 그대로 테이블 형태로 데이터를 저장한다. 사용자당 여러 개의 테이블을 소유할 수 있으며, 각 테이블은 다수의 컬럼으로 정의된 행을 포함한다. 그냥 편하게 RDBMS의 하나의 테이블이나, 엑셀 테이블 하나 생각하면 된다.


그런데 이미 RDBMS나 다른 곳에서도 제공하는 테이블 데이터 구조를 왜 따로 정의했을까? 쉽게 생각하면 요즘 유행하는 NoSQL과 비슷한 사상으로 생각하면 된다. 복잡한 관계형 구조나 Query가 필요 없지만 데이터의 양이 상당히 크고 고성능의 접근성이 요구될 때 사용된다. 트위터가 데이타를 Cassandra와 같은 NoSQL DB에 저장하고 사용하는 것과 같이 이유이다. Amazon의 SimpleDB와 유사한 서비스로 생각하면 된다.

Blob Storage
다음은 Blob Storage이다. 이미지,동영상 또는 큰 사이즈의 Binary 데이터등을 저장하는데 사용되는 서비스이다.


특징은 대용량의 저장성을 보장하고, 특히 CDN (Contents Distribution Network – 일종의 웹캐슁 서비스와 비슷하게 생각하면 된다. 각 지역 마다 캐쉬 서버를 두고 컨텐츠를 그 캐쉬 서버에 복제해서 지역적인 차이로 인한 다운로드 속도를 절감해준다.)과의 연동을 통해서 Blob Data를 원거리에서 접근하는데 성능을 보장한다.

SNS 서비스에서 이미지,동영상 저장 서비스나, 일반 기업에서 Archiving 서비스 (경비 지출서에 영수증등을 스캔해서 몇 년동안 저장해야 하는 기업 내부 규정)등에 유용하게 사용될 수 있다.

Disk Storage
Disk Storage 서비스는 Blob Storage 서비스를 Disk로 Mount 해놓은 서비스이다. Blob Storage가 API를 통해서 접근한다면, Disk Storage는 Application 입장에서는 하나의 물리적인 디스크로 인식하고 접근할 수 있다. 접근 성능을 높이기 위해서 Local VM에 (Windows Virtual Machine) Local Cache를 둬서 성능을 보장한다.

Queue Storage Service
 Queue Storage는 우리가 일반적으로 프로그래밍에서 사용하는 Queue를 생각하면 된다. IBM의 MQ나 Java의 JMS와 같은 개념이다.


이러한 Queuing 서비스는 비동기식 처리 방식의 아키텍쳐를 구현할 때 매우 편리한데, 예를 들어 월말 정산을 한다던지, 리포트 생성과 같은 배치 처리를 하고자 할 때, 화면에서 Request를 받고 백그라운드에서 처리를 할 때 유용하게 사용된다. 자바에서 JMS – Message Driven Bean(EJB)와 같은 아키텍쳐를 구축할 수 있다.

SQL Azure
마지막으로 SQL Azure이다. MS SQL Azure는 쉽게 이해하면 MS SQL RDBMS를 통째로 클라우드에 올려놨다고 생각하면 된다. RDBMS를 클라우드에서 사용할 수 있는 것이다. Amazon의 경우 EC2에 Oracle 이미지를 올려놓고 사용할 수 있지만 클라우드 플랫폼 자체에 녹여놨다고 보기는 약간 어렵지 않을까?

SQL Azure 서비스 중에 하나 중 재미있는 것은 MS SQL Azure 노드간의 데이터 동기화나 MS SQL Azure 노드와 기업내의 SQL 서버간의 데이터 동기화가 가능하다. MS SQL 제품 내부에는 CDC (Change Data Capture) 기능을 가지고 있는데, 아마 이 모듈을 사용해서 구축된 듯하다. 이서비스의 이름은 SQL Azure Data Sync Service로, 이 CDC 기능을 쉽게 Wrapping해놔서, Web UI상에서 복제할 MS SQL Instance를 선택하고, 테이블을 선택하면 자동으로 복제가 진행된다. 아무래도 센터간 복제이기 때문에 실시간 복제는 불가능하리라 생각하고, 아래 동영상을 보니 스케쥴 기반으로 복제를 진행한다.

아래 동영상의 시연을 보면 약 1132건의 트렌젝션 (테이블 생성에서부터, 복제등을 포함해서) 미국에서 유럽 센터간 동기화를 수행하는데 11.4초 정도가 소요된다.

기업 내부에서 CDC를 통해서 데이터 베이스를 동기화 하는 경우는 근 실시간으로 이루어 지는데, Azure Data Sync Service를 통한 지역간 복제는 아무래도 복제 아키텍쳐를 스케쥴 기반으로 설계해야 한다.

 

Groovy에서 간단 SQL SELECT

프로그래밍/Groovy | 2009.06.15 17:01 | Posted by 조대협
import groovy.sql.Sql

sql = Sql.newInstance("jdbc:oracle:thin:@localhost:1521:XE","BPEL"
,"BPEL","oracle.jdbc.driver.OracleDriver")

rows =[]
sql.eachRow("select * from PERF_OUT"){
rows << it.toRowResult()
}

println rows[1]["PK"] // 첫번째 ROW의 PK 컬럼을 출력

'프로그래밍 > Groovy' 카테고리의 다른 글

Groovy & Grails quick review.  (2) 2009.06.15
Groovy에서 간단 SQL SELECT  (0) 2009.06.15
TAG Groovy, sql

SQL Batch

프로그래밍/프로그래밍팁 | 2007.11.28 15:27 | Posted by 조대협

대용량 SQL을  한꺼번에 수행할때

for(..){
 pstmt.setXX
 pstmt.executeUpdateXX
}
tx.commit

이 코드는 느리다.
for(..){
 pstmt.setXX
 pstmt.addBatch
}
pstmt.executeBatchXX
tx.commit

이렇게 하는게 성능에 5~10배까지 차이가 난다.

===

아래는 직접 테스트 한 코드 10배 정도 차이가 나는것을 볼 수 있다.

<%

        Context ctx = new InitialContext();
        javax.sql.DataSource ds = (javax.sql.DataSource)
                ctx.lookup("bchoDS");
        Connection conn = ds.getConnection();
        conn.setAutoCommit(false);
        Statement stmt = conn.createStatement();
        stmt.executeUpdate("delete from bcho");
        conn.commit();
        stmt.close();

        long start = System.currentTimeMillis();
        out.println("start :"+start);

        String sql = "insert into bcho values( ?,'seoul')";
        PreparedStatement pstmt = conn.prepareStatement(sql);

        for(int j=0;j<10;j++){
          for(int i=0;i<10000;i++){
                pstmt.setString(1,"DUMMY");
                pstmt.executeUpdate();
          }
          Statement cstmt = conn.createStatement();
          cstmt.executeUpdate("commit work write batch nowait");
          cstmt.close();

        }// for j
        pstmt.close();
        conn.close();

        long end = System.currentTimeMillis();
        out.println("<BR>end :"+end);
        out.println("<BR>elapsed :"+(end-start));

%>


==== 아래는 BATCH

<%

        Context ctx = new InitialContext();
        javax.sql.DataSource ds = (javax.sql.DataSource)
                ctx.lookup("bchoDS");
        Connection conn = ds.getConnection();
        conn.setAutoCommit(false);
        Statement stmt = conn.createStatement();
        stmt.executeUpdate("delete from bcho");
        conn.commit();
        stmt.close();

        long start = System.currentTimeMillis();
        out.println("start :"+start);

        String sql = "insert into bcho values( ?,'seoul')";
        PreparedStatement pstmt = conn.prepareStatement(sql);

        for(int j=0;j<10;j++){
          for(int i=0;i<10000;i++){
                pstmt.setString(1,"DUMMY");
                pstmt.addBatch();
          }
          pstmt.executeBatch();
          conn.commit();

        }// for j
        pstmt.close();
        conn.close();

        long end = System.currentTimeMillis();
        out.println("<BR>end :"+end);
        out.println("<BR>elapsed :"+(end-start));

%>


BATCH elapsed :270  msec
COMMIT elapsed :24512 msec

===

애플리케이션에서 다른 업무와 함께 테스트 했을때는 2배 정도 차이가 났음.

'프로그래밍 > 프로그래밍팁' 카테고리의 다른 글

NIO  (0) 2008.02.27
JDK 1.5 부터 등장한 ThreadPool  (0) 2008.02.27
SQL Batch  (0) 2007.11.28
대용량 Record select  (0) 2007.11.28
Java Application의 Locking 처리문제  (0) 2007.08.21
업그레이드된 개발자 되기  (6) 2007.08.20