Header

  1. View current page

    pcguy7 개발 노트

Profile_image?t=1273412553&type=big
SAP 달인이 되는 그날까지~!
110

PrepareStatement 작동원리(최적화)

 

JDBC(Java Database Connectivity)
제목 : Prepared Statements의 중요성
글쓴이: 서정희(to2space) 2002/04/12 23:42:17 조회수:6140 줄수:389
[프린트]
          -----------------------------------------------
          ************************************************
          서정희 
          한솔 텔레컴 
          
          Why Prepared Statements are important and how to use them "properly"
          이글은 www.ejbinfo.com의 기사를 번역한 것입니다.
          v 1.0
          
          
          
          Technical translation
          서정희
          
          번역 혹은 기술상의 오류에 대해서 feedback을 주세요.
          to2space@kornet.net
          
          JDBC에 관련된 사항을 더 보실려면..
          http://home.megapass.co.kr/~to2space/
          
          
          번역하는 이의 수고도 생각하는 의미에서 꼭 출처는 명기해 주십시요.
          ************************************************
          ------------------------------------------------
          
          원문은 하단에 있습니다.
          Prepared Statement사용의 기본적인 원리를 기술하는 내용입니다.
          JDBC의 이해를 돕기 위해 번역해 보았습니다.
          
          
          
           
          Why Prepared Statements are important and how to use them "properly".
          
          왜 PreparedStatements는 중요하고 어떻게 이들을 “적절히” 이용해야할까요?
          데이터 베이스는 다루기 힘들다. 많은 수의 클라이언트로부터 동시에
          sql쿼리문을 받아들이고 많은 데이터에 대해서 가능한 효율적으로 쿼리를 실행한다.
          Statement들을 수행하는 것은 퍼포먼스를 많이 잡아 먹는 작업이지만 데이터 베이스들은
          현재 가능하다면 이런 오버헤드를 줄이는 방식으로 기록되어진다. 
          그러나 만약 우리가 최적화 과정에 중점을 둔다면 이러한 과정은 개발자의 도움을 
          필요로 한다. 이 기사는 정확한 PreparedStatements의 사용이 얼마나 데이터 베이스가
           이러한 최적화 과정을 도와 줄 수 있는지를 보여준다.
          
          
          How does a database execute a statement?
          
          어떻게 데이터 베이스가 statement를 수행할까요?
          분명히, 이 글에서는 많은 세부적인 것을 기대하지 마십시오. 
          우리는 단지 이 기사의 중요한 측면을 검증하기만 할 것입니다
          데이터 베이스가 하나의 statement를 받을 때 데이터 베이스 엔진은 처음 문장을
           parse시키고 잘못된 문법을 검사한다. 일단 statement가 parse되어지고 
          그런 다음 데이터 베이스는 statement 실행하기 위한 가장 효율적인 방법을 알아야한다. 
          이것은 계산상 아주 큰 비용이 들수가 있다.(서버 성능을 순간적으로 많이 잡아먹는다)
          데이터 베이스는 도움이 된다면 어떤 인덱스를 쓸것인지 혹은 테이블에 있는 모든 row를
          다 읽어야 하는 지를 확인한다. 결국 데이터 베이스는 무엇이 가장 좋은 방법인지를 
          이해하는데, 특정한 데이터에 대해서 통계를 이용한다.
          일단 쿼리 플랜query plan( 역자주 query를 얼마나 효율적으로 할 수 있는지에 
          대한 플랜, 미리 데이터 베이스는 플랜을 세운 후 쿼리를 진행한다.)이 이루어지면 
          이것은 데이터 베이스엔진에 의해 수행되어진다.
          이런 데이터에 대한 접근 계획의 생성은 cpu 전원을 소모 시킨다.
          관념적으로 만약 우리가 똑같은 statement 를 데이터 베이스에 두번째로 보낸다면
          우리는 데이터 베이스가 첫번 째 statement에대한 접근 계획을 재사용하도록 하는 것을 
          선호할 것이다. 이것은 또 한번 접근 계획을 생성 시키는 것 보다 적은 cpu점유율을 
          사용할 것이다.
          
          
          Statement Caches
          데이터 베이스들은 이런 방식으로 조절되어진다.
           데이터 베이스는 보통 일종의 statement cache을 가지고 있다. 
          이 cache는 statement 자체를 키로써 사용하고 데이터에 대한 접근 계획은 이 cache 속에
           대응되는 statement와 함께 저장되어 있다.
          이것은 데이터 베이스 엔진이 이전에 실행 되었던 statement들에 대한 플랜을
           재사용하게 한다. 예를 들어 만약 우리가 데이터 베이스에 
          “select a,b from t where c = 2”와 같은 statement를 보냈다면 계산된 실행 플랜은
           cache에 저장되어진다. 만약 우리가 똑같은 statement을 또다시 보내면 데이터 베이스는
           지난 번에 쓴 접근 계획을 재사용할 수 있게 되어서 cpu 사용율을 줄이게 해준다.
          
          전체 statement가 키라는 것을 주지하고, 예를 들어서 우리가 나중에 
          “select a,b from t where c = 3” 라는 statement를 보냈다면 
          이것은 접근 계획을 발견 할 수 없을지도 모를 것이다. 이것은 c=3이 cache에 저장된 
          플랜의 c=2와 다르기 때문이다.
          예를 들어,
          for(int I = 0; I < 1000; ++I) {
           PreparedStatement ps = conn.prepareStatement("select a,b from t where c = " + I);
           ResultSet rs = Ps.executeQuery();
           rs.close();
           ps.close();
           } 
          
          여기에서는 cache는 사용되지 않을 것이다. For loop의 각각의 I값에 해당하는 
          다른 sql문을 데이터 베이스에 보낸다. 새로운 접근 계획이 각각의 I 값의 해당하는 
          sql에 의해 계산되어지고 기본적으로 우리는 이런 접근 방식을 이용하므로써 cpu 사용을
           소모시켜 버린다. 그렇지만, 다음 예제를 보면
          PreparedStatement ps = conn.prepareStatement("select a,b from t where c = ?");
          for(int I = 0; I < 1000; ++I) {
           ps.setInt(1, I); 
           ResultSet rs = ps.executeQuery();
           rs.close();
           ps.close(); 
          }
          위의 예제는 더욱더 효율적일 것이다. 데이터 베이스에 보내어지는 위의 sql문에서 ? 
          표시는 대응되는 파라메터 값을 받고 있다. 이것은 모든 iteration에 해당하는 sql 
          문장이 하나의 같은 sql문장으로 "c=?" 에 대응되는 다른 파라메타 값과 함께
           데이터 베이스에 보내어진다는 것을 의미한다. 이것은 데이터 베이스가 위
           예제의 하나의 문장에 대한 접근 계획을 이용하게 하고 프로그램이 데이터 베이스 
          내부에서 더욱 더 효율적으로 수행되게 한다. 이것는 기본적으로 
          여러분의 애플리케이션이 더 빠르게 수행되게 하거나 또는 더 많은
           cpu 의 비점유 부분을 데이터 베이스의 다른 유저에게 제공 되게한다.
          
          
          PreparedStatements and J2EE servers
          
          우리가 J2EE서버를 이용할 때 상황은 좀더 복잡해질수 있다. 
          보통 a prepared statement는 하나의 단일 데이터 베이스 connection과 관련이 있다.
          Connection이 닫혔을 때 a prepared statement는 버려진다.
          보통 a fat Client무거운 클라이언트 애플리케이션(역자주 서버에 주요 비즈니스 로직을 
          두지 않고 클라이언트에 주요 비즈니스 로직을 둔 형태)은 connection을 하나 가지고 
          애플리케이션의 종료 시점까지 가지고 있다.
          이것은 또한 모든 prepared statement들을 “격력하게” 혹은 “완만하게” 만든다. 
          “격렬하게” eagerly라는 의미는 모든 prepared statement들이 애플리케이션이 
          시작할 때 한번에 만들어 진다는 것이고 “완만하게” 
          lazily의 의미는 a prepared statement들이 사용될 때에 만들어진다는 것이다. 
          전자는 애플리케이션이 기동할 때 지연 현상을 주나 기동하면 최적의 조건에서 잘 수행된다. 
          (역자 당연히 모든 prepared statement들이 만들어지므로 느리다)
          후자는 어떠한 사전의 준비가 이루어 지지 않는다 그러나 애플리케이션의 동작함에 따라
            prepared statement들이 애플리케이션에 의해 처음으로 사용되어질 때 
          prepared statement들은 만들어진다. 이것은 모든 문장들이 준비되었을 때까지 공평하지
           못한 성능을 나타낸다. 그러나 결국엔 애플리케이션이 안정적으로 수행되고 “격렬하게 
          수행되는 애플리케이션” 보다 빠른 성능을 나타낸다. 어떤 것이 최고냐는 여러분이 
          “빠른 시작을 원하는가?” 또는 “평균적인 성능을 원하는 가?”에 달려있다.
          J2EE 애플리케이션에 있어서의 문제는 이처럼 동작하지 않는 것이다.
           이것은 단지 하나의 요청 기간 동안 하나의 connection에 대해서 유지된다. 
          이는 요청이 실행될 때 마다 prepared statement들을 반드시 만들어야 한다는 의미다. 
          이것은 매번 요청이 될 때 마다 만들어지는 것보다 prepared statement들이 한번에
           만들어지는 무거운 클라이언트 접근 방식의 경우 만틈 효율적이지 않다. 
          J2EE 벤더들은 이를 알고 성능 감소를 피하기 위해서 connetion pooling을 
          디자인 하였다. J2EE 서버는 여러분의 애플리케이션에 하나의 connection을 제공했을 때,
           이것은 실질적인 connection이 아니라 여러분은 하나의 wrapper(역자주: 실질적인 
          connection이 아닌 벤더들에 의해 만들어지 새로운
          클래스에 의해 쌓여진 wrapped것을 말한다) 를 얻은 것이 된다.
          여러분은 이것을 주어진 connection에 대한 클래스의 이름을 보고 확인 할 수 있다.
           이것은 JDBC connecion는 아니고 여러분의 application server에 의해 만들어진 
          클래스일 것이다.
          모든 JDBC객체는 applicaion server의 커넥션 메니져에 의해 관리되어질 것이다. 
          모든 JDBC ResultSets, statements, CallableStatements, preparedStatements등은 
          wrapper되어서 proxy객체(역자 주 여기서는 실질적인 JDBC의 객체들connection,
          resultset등을 대신해서 application server에서 만들어진 클래스)로서 
          애플리케이션으로 제공될 것이다. 여러분이 Connection을 닫을 때 이들 객체는 
          무용하다고 표시되고 jvm에 의한 garbage collect가 이루어진다.
          보통 여러분이 하나의 connection를 닫으면 jdbc driver는 connection을 닫는다.
           우리는 이 connection이 J2EE 애플리케이션에 의해 close가 불려질 때 pool풀로
           되돌아갈수 있기를 원한다. 이렇게 하기 위해서 실제 connection과 유사한 
          proxy connetion을 만든다.
          이것은 실제의 connection의 reference를 가진다. 우리가 connection에 대해서 어떤 
          메소드를 호출할 때 이 proxy는 호출을 실질적인 conncetion으로 호출한다. 그러나 
          우리가 실질적인 connection의 close 메소드를 호출할 때 실제의 connection의 close를
           호출하는 대신 간단하게 connection을 connection pool에 반납한다. 
          그리고 proxy connection이 불필요하다는 표시를 한다, 만약 표신된 
          connection을 애플리케이션에 의해 다시 쓰여진다면 exception에러를 발생 시킬것이다.
          이 wrapping은 매우 유용하고 또 역시J2EE 애플리케이션 서버 수행을 도와 여러가지
           이해하기 쉬운 방법으로 prepared statements에 대한 도움을 줄것이다.
          애플리케이션이 Connection.prepareStatement을 호출할 때 이것은 driver에 의해
           a PreparedStatement 로 되돌아 간다. 애플리케이션은 connection을 가지고 있는
           동안 핸들을 유지하고 요청이 끝났을 때 Connection.prepareStatement를 닫고 
          connection을 닫는다. 그러나 connection이 pool로 반납된 후 나중에 같은 혹은 
          다른 애플리케이션에 의해 재사용된다면 그때 만약 그 애플리케이션이 또한 같은
           문장을 이상적으로 준비중이라면, 우리는 같은 PreparedStatement가 
          애플리케이션으로 가기를 원할 것이다.
          
          
          J2EE PreparedStatement Cache
          
          이것은 J2EE server connection pool manager에 있는 cache을 이용해서 이루어진다. 
          J2EE server는 풀에 있는 각각의 database connection에 대한 prepared statements 의
           모든 리스트를 유지 한다. 애플리케이션이 하나에 connection에 대해서
           prepared statement를 호출하면 서버는 그 문장이 미리 준비되어 있는가를 확인한다.
           만약 그것이 미리 준비 되었다면 PreparedStatement 객체가 cache속에 있을 것이고
           이것은 애플리케이션로 반환 된다. 만약 그렇지 않다면 이 호출은 
          jdbc driver로 넘겨지고 다시 쿼리/ PreparedStatement 객체가 그 connection cache에
           추가 된다. Jdbc driver가 이렇게 동작하기 때문에 우리는 connection마다 
          하나의 cache를 필요로한다. 우리가 이 cache의 잇점을 잘 이용하기 원한다면 
          앞에서 말한 바와 같이 파라메터화 된 쿼리를 사용해서 cache속에 미리 준비된 것을
           사용한다. 대부분의 애플리케이션 서버는 이 prepared statement cache의 사이즈를 
          조절 할 수 있도록 되어있다.
          
          
          Summary
          
          그래서 우리는 prepared statements를 파라메터와 함께 사용해야한다. 
          이것은 미리 만들어진 접근 계획을 재 사용하므로서 데이터 베이스에 대한 로드를 
          줄여 준다.
          이 cache는 데이터 베이스가 확장된 것이어서 여러분의 모든 애플리케이션이 
          유사한 파라메터화된 sql을 사용하면 하나의 애플리케이션이 다른 애플리케이션에
           의해 사용된 prepared statements를 이용하므로 캐시 스키마의 효율성을 증대 
          시킬 수 있다.
          이것은 application server 사용의 이점이다. 왜냐하면 데이터 베이스에 접근하는 
          로직은 데이터 접근 계층에 집중화 되어야하기 때문이다.
          두번째로 prepared statements의 올바른 사용은 또한 여러분이 애플리 케이션 내부의 
          prepared statements cache를 잘 이용할 수 있게 한다. 이것은 애플리케이션이 
          이전에 사용했던 prepared statements 호출을 재사용해서 JDBC driver에 대한 호출의
           수를 감소시켜 성능의 향상을 시킨다. 이것은 현명한 fat clients 사용을 효율적으로 
          그리고 경쟁력있게 만들고
          독점적인 connection을 유지할 수 없는 불이익을 제거한다.
          만약 파라메타화된 prepared statements를 사용한다면 여러분은 데이터 베이스와 
          코드를 가지고 있는 application server의 효율을 높일 수 있다. 이들 개선된 점은 
          여러분의 애플리케이션의 성능을 향상 시킬수 있게 할것이다.
          
          -------------------------------------------------------------
          다음번에는 java performance tuning에 대한 기사를 보내드립니다.
          -------------------------------------------------------------
          
          
          
          [원문]
          
          Why Prepared Statements are important and how to use them "properly".
          
          Databases have a tough job. 
          They accept SQL queries from many clients concurrently and
           execute the queries as efficiently as possible against the data.
           Processing statements can be an expensive operation but databases 
          are now written in such a way so that this overhead if minimized. But, 
          these optimizations need assistance from the application developers 
          if we are to capitalize on them. This article shows how the correct
           use of PreparedStatements can significantly help a database perform 
          these optimizations. 
          
          How does a database execute a statement?
          Obviously, don't expect a lot of detail here; we'll only examine the aspects 
          important to this article. When a database receives a statement then
           the database engine first parses the statement and looks for syntax errors. 
          Once the statement is parsed then the database needs to figure out the most 
          efficient way to execute the statement. This can be computationally quite 
          expensive. The database checks what indexes if any could help, or whether 
          it should do a full read of all rows in a table. Databases use statistics 
          on the data to figure out what is the best way. Once the query plan is created
           then it can be execute by the database engine. 
          It takes CPU power to do the access plan generation. Ideally, 
          if we send the same statement to the database twice then we'd like the database
           to reuse the access plan for the first statement. This uses less CPU than if
           it regenerated the plan another time. 
          
          Statement Caches
          Databases are tuned to do this. They usually include sort kind of statement cache.
          This cache uses the statement it-self as a key and the access plan is stored 
          in the cache with the corresponding statement. This allows the database engine
           to reuse the plans for statements that have been executed previously. 
          For example, if we sent the database a statement such as select a,b from 
          t where c = 2 then the computed access plan is cached. 
          If we send the same statement later then the database can reuse the 
          previous access plan thus giving us a saving in CPU power. 
          
          Note however that the whole statement is the key.
           So, for example if we later sent the statement 
          select a,b from t where c = 3 then it would not find an access plan. 
          This is because the c=3 is different from the cached plan "c=2". So, 
          for example: 
          for(int I = 0; I < 1000; ++I) { 
            PreparedStatement ps = conn.prepareStatement("select a,b from t where c = " + I);
            ResultSet rs = Ps.executeQuery(); rs.close(); ps.close(); 
          } 
          
          
          
          
          Here the cache won't be used. Each iteration of the loop sends a different
           SQL statement to the database. A new access plan is computed for each iteration 
          and basically, we're throwing CPU cycles away using this approach. How-ever,
           look at the next snippet: 
          
          PreparedStatement ps = conn.prepareStatement("select a,b from t where c = ?"); 
          for(int I = 0; I < 1000; ++I) { 
           ps.setInt(1, I); 
           ResultSet rs = ps.executeQuery(); 
           rs.close(); 
          } 
          ps.close(); 
          
          Here it will be much more efficient. The statement sent to the database 
          is parameterized using the '?' marker in the sql. This means every iteration 
          is sending the same statement to the database with different parameters for 
          the "c=?" part. This allows the database to reuse the access plans for the 
          statement and makes the program execute more efficiently inside the database. 
          This basically lets your application run faster or makes more CPU available to 
          users of the database. 
          
          PreparedStatement ps = conn.prepareStatement("select a,b from t where c = ?");
          for(int I = 0; I < 1000; ++I) {
          ps.setInt(1, I); 
          ResultSet rs = ps.executeQuery();
          rs.close();
          ps.close(); 
          }
           
          PreparedStatements and J2EE servers
          Things could be complicated when we use a J2EE server. Normally,
           a prepared statement is associated with a single database connection.
           When the connection is closed then the preparedstatement is discarded.
           Normally a fat client application would get a database connection and 
          then hold it for its lifetime. It would also create all prepared statements 
          either eagerly or lazily. Eagerly means that they are all created at once 
          when the application starts. Lazily means that they are created as they are used.
           An eager approach gives a delay when the application starts but once 
          it starts then it performs optimally. A lazy approach gives a fast start 
          (as no preparation is done) but as the application runs the prepared statements 
          are created when they are first used by the application. This gives an uneven
           performance until all statements are prepared but eventually the application 
          settles and runs as fast as the eager application. Which is best depends on
           whether you need a fast start or you need even performance. 
          
          The problem with a J2EE application is that it doesn't work like this.
           It only keeps a connection for the duration of the request. This means that 
          it must create the prepared statemes every time the request is executed.
           This is not as efficient as the fat client approach where the prepared 
          statements are created once rather than on every request. J2EE vendors have 
          noticed this and designed the connection pooling to avoid this performance 
          disadvantage. 
          When the J2EE server gives your application a connection, it isn't giving
           you the actual connection; you're getting a wrapper. 
          
          
          You can verify this by looking at the name of the class for the connection
           you are given. It won't be a database JDBC connection, it'll be a class 
          created by your application server. Every JDBC object will be proxied by 
          the application servers connection pool manager. All JDBC ResultSets, 
          statements, CallableStatements, preparedStatements etc will be wrapped 
          and returned to the application as a proxy object. When you close the 
          connection these objects are mark invalid and can be garbage collected. 
          
          
          Normally if you called close on a connection then the jdbc driver closes
           the connection. We want the connection to be returned to the pool when 
          close is called by a J2EE application. We do this by making a proxy jdbc 
          connection class that looks like a real connection. It has a reference to 
          the actual connection. When we invoke any method on the connection then the 
          proxy forwards the call to the real connection. But, when we call methods 
          such as close then instead of calling close on the real connection, it simply
           returns the connection to the connection pool and then marks the proxy 
          connection as invalid so that if it is used again by the application then 
          we'll get an exception. 
          
          This wrapping is very useful as it also helps J2EE application server
           implementers add support for prepared statements in a sensible way. 
          When an application calls Connection.prepareStatement then it is returned 
          a PreparedStatement object by the driver. The application then keeps the
           handle while it has the connection and those closes it before it closes 
          the connection when the request finishes. But, after the connection is 
          returned to the pool and later reused by the same or another application 
          then if that application also prepares the same statement then ideally, 
          we want the same PreparedStatement to be returned to the application. 
          
          J2EE PreparedStatement Cache
          This is implemented using a cache inside the J2EE server connection pool manager.
           The J2EE server keeps a list of prepared statements for each database connection 
          in the pool. When an application calls prepareStatement on a connection then the
           app server checks if that statement was previously prepared. If it was then the 
          PreparedStatement object will be in the cache and this is returned to the 
          application. If not then the call is passed to the jdbc driver and then 
          query/preparedstatement object is added in that connections cache. 
          We need a cache per connection because that's the way jdbc drivers work. 
          Any preparedstatements returned are specific to that connection. 
          If we want to take advantage of this cache then the same rules apply 
          as before. We need to use parameterized queries so that
           they will match ones already prepared in the cache. 
          Most application servers will allow you to tune the size of this prepared 
          statement cache. 
          
          Summary
          So, we absolutely must use parameterized queries with prepared statements. 
          This reduces the load on the database by allowing it to reuse access plans
           that were already prepared. This cache is database wide so if you can arrange for
           all your applications to use similar parameterized SQL then you improve
           the efficiency of this caching scheme as an application can take advantage 
          of prepared statements used by another application. This is an advantage of 
          an application server because logic that accesses the database should be 
          centralized in a data access layer (either an OR-mapper, entity beans or 
          straight JDBC). This makes it easier to assure this. 
          Secondly, the correct use of prepared statements also lets you take advantage 
          of the prepared statement cache in the application server. 
          This improves the performance of your application as the application can reduce 
          the number of calls to the JDBC driver when it can reuse a previous prepared 
          statement call. This makes it competitive with fat clients efficiency wise and
           removes the disadvantage of not being able to keep a dedicated connection. 
          If you use parameterized prepared statements then you improve the efficiency 
          of the database and of your application server hosted code.
           Both of these improvements will allow your application to improve its performance. 
          
          
제목 : Re: Prepared Statements를 쓰지 않아야 할때.
글쓴이: 배경열(kybae) 2002/04/13 09:13:48 조회수:2044 줄수:31
          PreparedStatement가 SQL문의 수행계획을 재사용할 수 있는 장점이 있지만
          그것은 역으로 말하면 치명적인 약점이 될 수 있습니다.
          
          예를들어)
          select하는 테이블의 특정칼럼에 'A'라는 데이터와 'B'라는 데이터가 존재하고
          그 분포도가 A=99%, B=1%만 존재한다면 SQL문의 검색조건이 'B'를 검색할경우
          테이블의 Index를 타는것이 바람직하지만 'A'를 검색할경우 전체 테이블을 스켄해야
          할것입니다.
          
          하지만 PreparedStatement로 어느 조건을 검색하든지간에 한번 수행된 이후로는
          Query 실행 계획을 재사용 함으로서 앞으로 수행되는 Query의 식은 무조건 Index를 
          타거나 또는 무조건 FullScan을 하는 형태로 실행계획을 수립할 것입니다.
          
          이는 통계데이터를 적절히 활용하지 못하게되는 치명적인 오류가 발생할 수 있음을
          이야기 할 수 있습니다.
          
          따라서 제 짧은 소견으로는 실행계획이 특정 값에 의해 크게 바뀌는 것이 아닌경우엔
          PreparedStatement의 SQL Execution plan재사용이 효율적이라고 볼 수 있으며 반면에
          특정 값에 따라 실행계획을 재생성 해야 할 경우엔 Statment를 사용하는것이 바람직
          할 수 있습니다. 왜냐면 실행계획을 재생성하는것은 아주 짧은 시간에 수행 될 수 있
          지만 한번 잘못 생성된 실행계획에 의해 수행되는 SQL문은 엄청난 시간적 비용을 낭비
          할수 있습니다.
          
          일반적으로 OLTP성 업무엔 PreparedStatement사용하여 Plan재사용을 유도하며 반면
          OLAP와 같이 잦은 SQL문 수행은 발생하지 않지만 많은 량의 데이터를 처리해야 할때는 
          Statement를 사용하는것이 바람직하다고 할 수 있습니다.
          
          들리는 이야기로는 요즘 DBMS는 너무나 그 지능이 좋아서 PreparedStatement를 쓸지라도 
          너무 많은 Resource를 지속적으로 사용할 경우 실행계획을 재수립 한다고도 하는군요.
          
          결론적으로 Prepared Statement가 만능 해결사는 아니라는 것을 말씀드리고 싶습니다.
          
제목 : Re: 저의 PreparedStatement에 대한 생각을 쓰겠습니다.
글쓴이: 서민구(4baf) 2002/04/13 11:39:06 조회수:1042 줄수:42
          예를들어)
          select하는 테이블의 특정칼럼에 'A'라는 데이터와 'B'라는 데이터가 존재하고
          그 분포도가 A=99%, B=1%만 존재한다면 SQL문의 검색조건이 'B'를 검색할경우
          테이블의 Index를 타는것이 바람직하지만 'A'를 검색할경우 전체 테이블을 스켄해야
          할것입니다.
          
          하지만 PreparedStatement로 어느 조건을 검색하든지간에 한번 수행된 이후로는
          Query 실행 계획을 재사용 함으로서 앞으로 수행되는 Query의 식은 무조건 Index를 
          타거나 또는 무조건 FullScan을 하는 형태로 실행계획을 수립할 것입니다.
          
          ->
          
          SELECT * FROM EXP_TABLE
          WHERE :id = 'A'
          AND id||'' = 'A'
          UNION ALL
          SELECT * FROM EXP_TABLE
          WHERE :id = 'B'
          AND  = 'B'
          
          RBO의 경우 만약 말씀하신대로 정확한 분포도를 사전 예측가능하다면 
          
          위에처럼 SQL만 잘 쓰면 됩니다.
          
          그리고, CBO를 쓰실거라면 플랜이 바뀌면 플랜이 invalidate되므로 상관없고요.
          
          
          들리는 이야기로는 요즘 DBMS는 너무나 그 지능이 좋아서 PreparedStatement를 쓸지라도 
          너무 많은 Resource를 지속적으로 사용할 경우 실행계획을 재수립 한다고도 하는군요.
          
          -> 오라클의 경우에는 아마 이런게 없을겁니다.
          
          만약 자동화된 것을 원하신다면 크론잡이나 DBMS_JOB으로 종종 analyze만 돌려주면
          될겁니다.
          
          
          즐프하세요
          
          -----------------------------------------------
          OCP, SCJP
          Software Engineer
          Seo, Min-Koo(4baf@dreamwiz.com)
          
제목 : Re: 좋은 방법이네요.
글쓴이: 배경열(kybae) 2002/04/16 08:01:47 조회수:688 줄수:4
          어떤 값이 들어있고 분포도만 정확히 안다면 UNION ALL로 고려해서
          Prepared Statement를 쓰면 되겠네요.. 근데 값이 여러가지거나 로직이 복잡해지면
          사용하기는 좀 어렵겠네요.. --;;;
          실행계획에 대한 invalidation checking기능이 오라클 9i에서도 없나요?
          
제목 : Re: 글쎄요.. ^^ invalidation checking?
글쓴이: 서민구(4baf) 2002/04/18 11:18:03 조회수:643 줄수:18
          길고 복잡한 SQL문장이 사용하기 어렵습니다.
          퀵소트는 버블소트보다 어렵습니다.
          
          무슨말을 하고싶은지 아시리라 생각합니다. ^^;
          
          제가 뭐 천재라고 저런 SQL문을 써대는 것은 아니고..
          잘아시는 대용량 데이터베이스 솔루션중의 일부내용입니다.
          안보셨으면 한번 보시길 바라고요.
          
          오라클 9i의 새기능에 대해서는 본격적으로 학습해본적이 없지만,
          제가 알기로 '잘 실행되는 SQL에서 어느날 갑자기 비용이 너무 많이 들게되는순간
          plan 이 invalidate된다' 는 기능은 없습니다.
          
          
          -----------------------------------------------
          OCP, SCJP
          Software Engineer
          Seo, Min-Koo(4baf@dreamwiz.com)
          
제목 : Re: [질문] prepared Statement의 캐쉬 장소?
글쓴이: 조현길(guest) 2002/04/20 03:24:18 조회수:718 줄수:11
          위에 분 번역 감사드립니다. ^^ prepared Stratement 에 관해서 궁금한 점이 있습니다.
          prepared Statment 가 sql 처리 과정중 syntex check, 와 symentics check, 실행계획을
          재사용하는 거라는 것은 이해가 갑니다만, 이러한 사항에 대한 캐쉬가 DBMS가 아닌 
          Application Server 에 존재한다는 것이 이해가 안 갑니다. JDBC 나  Application Server
          스펙상에 그렇게 정의된 것인가요? 만약 캐쉬가 Application  Server 에 존재한다면 
          해당 쿼리가 날아왔을때  JDBC 드라이버는 쿼리스트링이 아닌 캐쉬된 내용을 DBMS 로
          전송하게 되는 것인지요? ^^ 궁금하네요.
          
          ------------------------------------------------
          Simple Coder 
          Cho, Hyungil (gedwarp@netsgo.com)
          
제목 : Re: WebLogic에서의 PreparedStatement Cache
글쓴이: 서정희(to2space) 2002/06/05 23:20:23 조회수:3917 줄수:148
          ************************************************
          서정희 
          한솔 텔레컴 
          
          번역 혹은 기술상의 오류에 대해서 feedback을 주세요.
          to2space@kornet.net
          
          JDBC에 관련된 사항을 더 보실려면..
          http://home.megapass.co.kr/~to2space/
          
          번역하는 이의 수고도 생각하는 의미에서 꼭 출처는 명기해 주십시요.
          ************************************************
          
          궁금하신 부분에 대한 글입니다. 여기서의 예는 weblogic에 대한 사항입니다. 번역은 하지
          않았고 글도 궁금하신 부분에 대해서 100%의 설명은 되지는 않지만 그래도 읽어 보시면
          어느 정도 이해가 가실겁니다.
          
          For each connection pool that you create in WebLogic Server,
          you can specify a prepared statement cache size.
          When you set the prepared statement cache size, WebLogic Server stores 
          each prepared statement used in applications and EJBs
           until it reaches the number of prepared statements that you specify. 
          For example, if you set the prepared statement cache size to 10, WebLogic Server
           will store the first 10 prepared statements called by applications or EJBs. 
          
          When an application or EJB calls any of the prepared statements stored 
          in the cache, WebLogic Server reuses the statement stored in the cache. 
          Reusing prepared statements eliminates the need for parsing statements 
          in the database, which reduces CPU usage on the database machine, 
          improving performance for the current statement and leaving CPU cycles 
          for other tasks.
          
          The default value for prepared statement cache size is 0. 
          You can use the following methods to set the prepared statement cache size
           for a connection pool:
          
          
          Using the Administration Console. See Creating and Configuring a JDBC Connection 
          Pool in the Administration Console Online Help. 
          
          Using the WebLogic management API. See the getPreparedStatementCacheSize() 
          and setPreparedStatementCacheSize(int cacheSize) methods in the Javadocs
           for WebLogic Classes. 
          
          Directly in the configuration file (typically config.xml). 
          To set the prepared statement cache size for a connection pool 
          using the configuration file, before starting the server, 
          open the config.xml file in an editor, then add an entry 
          for the PreparedStatementCacheSize attribute in the JDBCConnectionPool tag.
           For example:
          
              <JDBCConnectionPool CapacityIncrement="5"       
           DriverName="com.pointbase.jdbc.jdbcUniversalDriver"       
           InitialCapacity="5" MaxCapacity="20" Name="demoPool"      
            Password="{3DES}ANfMduXgaaGMeS8+CR1xoA=="      
            PreparedStatementCacheSize="20" Properties="user=examples"    
              RefreshMinutes="0" ShrinkPeriodMinutes="15"       
           ShrinkingEnabled="true" Targets="examplesServer"      
            TestConnectionsOnRelease="false"      
            TestConnectionsOnReserve="false"     
             URL="jdbc:pointbase:server://localhost/demo"/>
          Usage Restrictions for the Prepared Statement Cache
          
          Using the prepared statement cache can dramatically increase performance,
           but you must consider its limitations before you decide to use it.
           Please note the following restrictions when using the prepared statement cache. 
          
          There may be other issues related to caching prepared statements
           that are not listed here. If you see errors in your system related 
          to prepared statements, you should set the prepared statement cache size to 0, 
          which turns off prepared statement caching, to test
           if the problem is caused by caching prepared statements.
          
          Calling a Stored Prepared Statement After a Database Change May Cause Errors
          
          Prepared statements stored in the cache refer to specific database objects 
          at the time the prepared statement is cached. If you perform any DDL 
          (data definition language) operations on database objects referenced 
          in prepared statements stored in the cache, the statements will fail 
          the next time you run them. For example, if you cache a statement
           such as select * from emp and then drop and recreate the emp table, 
          the next time you run the cached statement, the statement will fail
           because the exact emp table that existed when the statement was prepared,
           no longer exists. 
          
          Likewise, prepared statements are bound to the data type for each column
           in a table in the database at the time the prepared statement is cached. 
          If you add, delete, or rearrange columns in a table, prepared statements
           stored in the cache are likely to fail when run again.
          
          Using setNull In a Prepared Statement
          
          When using the WebLogic jDriver for Oracle to connect to the database, 
          if you cache a prepared statement that uses a setNull bind variable,
           you must set the variable to the proper data type. 
          If you use a generic data type, as in the following example,
           the statement will fail when it runs with a value other than null.
          
          java.sql.Types.Long sal=null
          ...
          if (sal == null)    setNull(2,int)//This is incorrectelse    setLong(2,sal) 
          Instead, use the following:
          
          if (sal == null)    setNull(2,long)//This is correctelse    setLong(2,sal) 
          This issue occurs consistently when using the WebLogic jDriver for Oracle.
           It may occur when using other JDBC drivers.
          
          Prepared Statements in the Cache May Reserve Database Cursors
          
          When WebLogic Server caches a prepared statement, the prepared statement
           may open a cursor in the database. If you cache too many statements,
           you may exceed the limit of open cursors for a connection. 
          To avoid exceeding the limit of open cursors for a connection, 
          you can change the limit in your database management system or 
          you can reduce the prepared statement cache size for the connection pool.
          
          Determining the Proper Prepared Statement Cache Size
          
          To determine the optimum setting for the prepared statement cache size,
           you can emulate your server workload in your development environment and
           then run the Oracle statspack script. In the output from the script,
           look at the number of parses per second. As you increase 
          the prepared statement cache size, the number of parses 
          per second should decrease. Incrementally increase the prepared statement cache 
          size until the number or parses per second no longer decreases.
          
          Note: Consider the usage restrictions for the prepared statement cache 
          before you decide to use it in your production environment. 
          See Usage Restrictions for the Prepared Statement Cache for more information.
          
          Using a Startup Class to Load the Prepared Statement Cache
          
          To make the best use of the prepared statement cache and 
          to get the best performance, you may want to create a startup class 
          that calls each of the prepared statements that you want to store
           in the prepared statement cache. WebLogic Server caches prepared statements 
          in the order that they are used and stops caching statements 
          when it reaches the prepared statement cache size limit. 
          By creating a startup class that calls the prepared statements 
          that you want to cache, you can fill the cache with statements 
          that your applications will reuse, rather than with statements t
          hat are called only a few times, thus getting the best performance
           increase with the least number of cached statements. 
          You can also avoid caching prepared statements that my be problematic, 
          such as those described in Usage Restrictions for the Prepared Statement Cache.
          
          Even if the startup class fails, WebLogic Server loads and caches the statements
          for future use.
          

History

Last edited on 04/10/2008 03:38 by pcguy7