Statement vs Preparedstatement

HunkiKim·2022년 9월 23일
0

Statement vs Preparedstatement

둘 다 SQL을 실행할 수 있는 객체라고 보면 된다. 하지만 둘은 몇가지 차이가 있다. 현재에는 대부분 preparedstatement방식을 사용한다고 보면 된다.

Statement

간단하게 Statement는 명령문이라고 보면 된다. 이는 DB에 작업을 명령하는 쿼리 등, 명령 그 자체를 말하는 것이라고 봐도 된다.

java기준으로 말하면 보통 SQL을 실행하는 객체로 JAVA에 존재한다. Connection 객체로 연결을 한 후 , QUERY 작업을 수행하기 위해 사용한다.

또한 매번 컴파일을 수행해야 한다. 완전히 같은 SQL문 같은 경우는 캐싱이 가능 하지만 파라미터만 달라져도 다른 SQL문으로 인식하여 구문분석과 실행계획을 다시 작성한다. 여기서 실행계획이란 사용자가 SQL을 실행하여 데이터를 추출하려고 할 때 옵티마이저가 수립하는 작업 절차이다.

실행계획은 짧게 말하면 SQL이 실행되는데 필요한 cost를 계산하고 어떤 방식으로 실행하는 것이 가장 좋은지를 판단한다. SQL이 데이터베이스에 전달되면 데이터베이스는 여러 단계를 거쳐서 해당 SQL을 어떤 순서와 방식으로 처리할 것인지 계획을 세우게 된다.

또한 쿼리문에 값이 미리 입력되어 있어야 한다. 따라서 쿼리에 인자를 부여할 수 없다. 이 때문에 정적인 쿼리문을 처리하는 정적 쿼리라고 할 수 있다.

PrepareStatement

데이터베이스 관리 시스템(DBMS)에서 동일하거나 비슷한 데이터베이스 문을 높은 효율성으로 반복적으로 실행하기 위해 사용되는 기술을 말한다.

동작 방식에 대해 말하면
1. 준비(Prepare) : 애플리케이션의 문의 틀을 만들고 이를 DBMS로 보낸다. 특정값은 지정하지 않은 채로 남겨진다.

  • (INSERT INTO products (name, age) VALUES(?, ?));
  1. 그 다음, DBMS는 문의 틀을 컴파일하며(최적화 및 변환) 아직 실행하지 않고 결과만 저장한다.
  2. 실행(Execute) : 나중에 App가 문 틀의 변수에 값(Bind)을 지정하면 DBMS는 (결과를 반환할 수도 있는) 문을 실행한다. 애플리케이션은 여러 값으로 원하는 횟수만큼 문을 실행할 수 있다.
  • 위의 예에서 첫 번째 변수에 "name", 두 번째 변수로 "27"을 지정한다.

위의 과정은 Statement에서도 동일하게 실행된다. 즉 실행까지는 동일하게 실행된다.

이는 SQL문장이 미리 컴파일되고, 실행 시간동안 인수값을 위한 공간은 확보할 수 있다는 점에서 Statement객체와 다르다. 이러한 부분에서 동적 쿼리라고 할 수 있다. 또한 Statement 객체의 SQL은 실행될 때 매번 서버에서 분석해야 하지만, PreparedStatement 객체는 한 번 분석되면 재사용아 용아허다. 또한 위치홀더(placeholder)를 사용하여 SQL 문장을 정의할 수 있게 해준다. 위치홀더는 ?로 표현된다.
여기서 그러면 무슨 차이가 있는 것인가.

차이점

statement는 실행할 때마다 컴파일을 하게된다. 즉 Parsing -> Compile -> Execute 과정을 거치게 된다. preparedStatement는 미리 컴파일되어 준비하고 있다.

Parsing -> Compile -> Exuecte 과정에서 둘 다 컴파일 발생시 쿼리로 쿼리로 접근 계획이 캐싱된다. 그리고 Statement 또한 완전히 일치하는 쿼리를 요청하면 컴파일을 건너뛰고 실행된다. 하지만 Statementsms Parsing -> Compile에 무조건 적인 접근을 하지만, PreparedStatement는 Caching된 PreoaredStatement객체로 DB에 쿼리를 요청하기 때문에 바로 Execute를 하게된다.

  • 오라클 문서 참조
    오라클에서는 close()를 할 때 자동적으로 prepared,callable statement에 대해 캐시를 한다. plain statement들은 암묵적으로 캐시되지 않는다. 왜냐하면 implicit statement caching이 한 key로서 sql string을 사용하고 있기 때문이다. 그리고 plain statement들은 SQL String없이 실행될 수 없다. 그러므로 implicit statement caching은 오직 OraclePreparedStatement and OracleCallableStatement objects에서 적용한다.

한줄 요약 : statement는 아무리 캐싱이 있다고 해도 parsing은 무조건 해야하지만 preparedstatement는 Caching된 preparedstatement객체로 DB에 쿼리를 바로 요청하기 때문에 구문 분석 과정은 뛰어넘게 된다.

하지만 이 또한 결국 너무 많아지면 Caching 영역이 커져 의미가 없어질 수 있다.

그리고 Statement는 인자를 다이나믹 쿼리로 작성하기 때문에 SQL Injection에 취약할 수 있기 때문에 따로 필터나 방어로직이 필요하다. 즉 인자를 SQL문으로 받기 때문에 DELETE문과 같은 SQL문을 보내게 되면 큰일난다.

결론적으로 Statement는 DDL(CREATE, ALTER, DROP) 구문에 적합하다. Prepared Statement는 DML(SELECT, INSERT, UPDATE, DELETE)구문 처리에 적합하다.

한줄 요약 : 쿼리문을 실행할 때 구문분석->컴파일->실행단계 과정에서 Statement는 이러한 과정이 매일 일어나는 반면, PreparedStatement의 경우 처음만 위 과정을 거친 후에 캐싱된 실행계획을 재사용하므로 DB 부하를 줄일 수 있다.

또한 값으로 Date,Time등 toString이 필요한 것들은 Statement에 들어갈 수 없다. 쿼리문 그대로 넣어줘야 하기 때문이다.

참고 자료 : https://docs.oracle.com/cd/B10501_01/java.920/a96654/stmtcach.htm

0개의 댓글