MySQL operator IN() 궁금증(or와 성능 차이? 조건 개수 제한?)

배열로 받은 Query parameter 내에 해당하는 데이터를 반환하는 API를 작성 중이다.
처음에는 조건을 전부 OR()로 연결하다가… 생각해보니 MySQL에는 이런 경우를 위한 operator IN()이 있다.
MySQL IN() operator 관련 궁금증이 생겨 알아보았다.

IN() 설명 및 사용법

IN(value, ...): IN() 리스트 안 값(value) 중 일치하는 게 있다면 1(true), 없으면 0(false)를 반환한다.

mysql> SELECT 2 IN (0,3,5,7);
        -> 0
mysql> SELECT 'wefwf' IN ('wee','wefwf','weg');
        -> 1

IN() 목록에는 개수 제한이 있을까?

IN() MySQL 문서를 읽어봤다.

The number of values in the IN() list is only limited by the max_allowed_packet value.

MySQL의 Server System Variables 중 하나인 max_allowed_packet 값에 의한 제한 외에는 별다른 제한은 없다. 즉, MySQL 서버와 주고 받는 하나의 패킷 크기 제한 값을 초과하지만 않는다면 개수 제한은 없다.

OR()IN() 성능 차이가 있을까?

결론부터 말하면 있다!
내가 직접 테스트해보지는 않았지만, 같은 질문을 던진 StackOverflow의 여러 답을 보면 꽤 많은 성능 차이를 보인다.
그럼 왜 이런 성능 차이가 있을까? O’Reilly 출판사에서 제공한 High Performance MySQL, 2nd Edition(Jeremy D. Zawodny) 책 일부에 따르면 다음과 같다.

In many database servers, IN() is just a synonym for multiple OR clauses, because the two are logically equivalent. Not so in MySQL, which sorts the values in the IN() list and uses a fast binary search to see whether a value is in the list. This is O(Log n) in the size of the list, whereas an equivalent series of OR clauses is O(n) in the size of the list (i.e., much slower for large lists)

많은 데이터베이스 서버에서 IN()과 multiple OR() 절은 그저 동의어로 쓰인다. 둘은 논리적으로 같은 기능이기 때문이다. MySQL에서는 다르다. MySQL은 IN() 리스트 안의 값을 정렬하고, 해당 값이 배열 안에 있는지 찾고자 빠른 이진 탐색을 이용한다. IN()의 경우 리스트 크기(n)에 따라 시간 복잡도가 O(Log n)인 반면, 연속된 OR() 절은 시간 복잡도가 O(n)이다. (즉, 리스트 크기가 클 수록 OR()IN() 보다 훨씬 느려진다.)

결국, IN()은 배열을 정렬하고 이진탐색을 하기 때문에, 하나씩 다 탐색하는 OR() 보다 빠르다는 결론! 리스트가 클 수록 IN()을 사용하는 편이 낫다.


단순 궁금증으로 시작했는데 꽤 많은 정보를 알게 됐다. 역시 개발자는 컴퓨터공학 기초 지식이 중요하다는 생각이 든다.

참고자료