Computer >> 컴퓨터 >  >> 프로그래밍 >> MySQL

JDBC에서 PreparedStatement가 Statement보다 빠른 이유는? 핵심 원리 쉽게 이해하기

Java 애플리케이션에서 데이터베이스 작업을 처리할 때 StatementPreparedStatement 중 어떤 것을 사용하느냐에 따라 성능에 큰 차이가 발생할 수 있습니다. 특히 대량의 INSERT 작업을 수행할 때 그 차이는 더욱 두드러집니다.

Statement 객체의 문제점

Statement 객체를 사용해 SQL 문을 실행하면, 특히 INSERT 문을 반복 실행하는 경우 매번 쿼리 전체가 다시 컴파일되고 실행됩니다. 그런데 자세히 보면 이 문장들 사이의 유일한 차이점은 값(value)뿐입니다. 쿼리 구조 자체는 동일한데도 불구하고 말이죠.

PreparedStatement의 동작 방식

반면 PreparedStatement는 사전 컴파일(precompiled)된 문장입니다. 즉, 쿼리가 한 번 컴파일되어 데이터베이스에 저장되며, 실제 값이 들어갈 자리에는 플레이스홀더(?)를 사용합니다. 이후 setter 메서드를 통해 값을 나중에 공급하게 됩니다.

이러한 방식 덕분에 동일한 쿼리를 반복 실행할 때 불필요한 컴파일과 실행 과정을 생략할 수 있어 성능이 크게 향상됩니다.

예제로 살펴보기

데이터베이스에 mobile_brandunit_sale이라는 두 컬럼을 가진 Dataset 테이블이 있다고 가정해 보겠습니다.

Statement 객체를 사용한 경우

Statement 객체로 이 테이블에 레코드를 삽입하면 코드는 다음과 같습니다:

stmt.executeUpdate("insert into Dataset values('Iphone', 3000)");
stmt.executeUpdate("insert into Dataset values('Samsung', 4000)");
stmt.executeUpdate("insert into Dataset values('Nokia', 5000)");
stmt.executeUpdate("insert into Dataset values('Vivo', 1500)");
stmt.executeUpdate("insert into Dataset values('Oppo', 9000)");
stmt.executeUpdate("insert into Dataset values('MI', 6400)");
stmt.executeUpdate("insert into Dataset values('MotoG', 4360)");
stmt.executeUpdate("insert into Dataset values('Lenovo', 4100)");
stmt.executeUpdate("insert into Dataset values('RedMi', 4000)");
stmt.executeUpdate("insert into Dataset values('OnePlus', 6334)");

executeUpdate() 메서드가 호출될 때마다 해당 문장 전체가 매번 컴파일되고 실행됩니다. 하지만 잘 살펴보면 변경되는 부분은 문장의 값뿐이고, 나머지 쿼리 구조는 불필요하게 계속 컴파일되고 있는 것입니다.

PreparedStatement를 사용한 경우

동일한 데이터를 같은 테이블에 삽입하되 PreparedStatement를 활용하면 코드는 다음과 같습니다:

PreparedStatement pstmt = con.prepareStatement("insert into Dataset values(?, ?)");

pstmt.setString(1, "Iphone");
pstmt.setInt(2, 3000);
pstmt.executeUpdate();

pstmt.setString(1, "Samsung");
pstmt.setInt(2, 4000);
pstmt.executeUpdate();

pstmt.setString(1, "Nokia");
pstmt.setInt(2, 5000);
pstmt.executeUpdate();

pstmt.setString(1, "Vivo");
pstmt.setInt(2, 1500);
pstmt.executeUpdate();

pstmt.setString(1, "Oppo");
pstmt.setInt(2, 9000);
pstmt.executeUpdate();

pstmt.setString(1, "MI");
pstmt.setInt(2, 6400);
pstmt.executeUpdate();

pstmt.setString(1, "MotoG");
pstmt.setInt(2, 4360);
pstmt.executeUpdate();

pstmt.setString(1, "Lenovo");
pstmt.setInt(2, 4100);
pstmt.executeUpdate();

pstmt.setString(1, "RedMi");
pstmt.setInt(2, 4000);
pstmt.executeUpdate();

pstmt.setString(1, "OnePlus");
pstmt.setInt(2, 6334);
pstmt.executeUpdate();

여기서는 INSERT 쿼리가 플레이스홀더(?)와 함께 준비되고, 이 쿼리는 한 번만 컴파일되어 데이터베이스에 저장됩니다. 이후 PreparedStatement 인터페이스의 setter 메서드(setString(), setInt() 등)를 통해 값만 전달하므로, 문장의 불필요한 재컴파일 없이 효율적으로 실행됩니다.

결론

PreparedStatement가 Statement보다 빠른 핵심 이유는 쿼리를 한 번만 컴파일하고 재사용하기 때문입니다. 동일한 구조의 쿼리를 여러 번 실행해야 하는 상황이라면 PreparedStatement를 사용하는 것이 성능 면에서 훨씬 유리합니다. 또한 PreparedStatement는 SQL 인젝션 공격을 방어하는 보안상의 장점도 함께 제공하므로, 실무에서는 가능한 한 PreparedStatement 사용을 권장합니다.