오늘은 mysql에서 in 연산자에 대해 간단하게만 알아봅시다.

 

 

operand IN(list)

 

 

 결론부터 말하면, 피연산자 operand의 값이, list에 속해있는 집합에 속해 있다면 참을 리턴합니다. 이 IN 연산자 안에는 sub Query 또한 들어갈 수 있을 겁니다. 그런 예는 서브 쿼리를 다룰 때 다시 언급해 드리도록 하겠습니다. 오늘은 간단하게 어떻게 쓰는지만 아시면 좋을 듯 싶습니다.

 

 


 

 먼저, country라는 테이블에서 에서, Code가 'CHN'이거나, 'KOR'이거나 'JPN'인 레코드를 찾으라는 쿼리가 들어온 경우, 요렇게 작성할 수 있습니다. where에 조건절 3개가 OR로 이어져 있습니다. 그런데 이것을 in 연산자로 바꿀 수 있어요.

 

 

 우리가 찾아야 하는, 그러니까 Code의 값이여야 하는 집합이 각각 'CHN', 'KOR', 'JPN'입니다. 이렇게 써도, 같은 결과가 나옵니다. 왜냐하면 Code의 값이 집합 A = {'CHN', 'JPN', 'KOR'}에 존재하면 참을 리턴하는데, 만약에 이 값이 세 값 중 어느 것도 아니라면, 예를 들어 'MOD'라면, A에 존재하지 않으니까 false를 리턴할 거에요. 

 

 

 쿼리의 수행 결과는 다음과 같습니다.

 

 


 이제 2번째 예제를 보도록 합시다.

 

 

 worker 테이블에 있는 모든 레코드들을 출력하면 아래와 같습니다.

 

 

 이 중에서 우리는 _name이 'A'나 'E'나 'a'나 'e'로 시작하는 사람들을 찾으려고 합니다. 그러면 어떻게 해야 할까요? 사실, 저번에 배운 regexp를 이용한다면 꽤 쉽게 작성할 수 있습니다. regexp '^(A|a|E|e)' 이렇게 작성하면 될 거에요. 제가 보통 작성하는 방식은 '^[AaEe]'입니다. 그런데 이것을 다르게 작성할 수도 있는데요.

 

 left(string,num)은 string에서 0번째부터 num-1번째 까지의 부분 문자열을 리턴합니다. 예를 들어서 str이 'abcde'라고 한다면 left(str,1)의 값은 'a'이고, left(str,2)는 'ab'입니다.

 

 

 그러면 우리는 _name이 'A'나 'E'나 'a'나 'e'로 시작하는지를 검사하려면 left(_name,1)을 먼저 호출하면 됩니다. 이 리턴값이 어느 집합에 속하면 되나요? {'A', 'E', 'a', 'e'}에 속하면 됩니다. 따라서, 위와 같이 쿼리를 작성하면 됩니다.

 

 

 쿼리의 수행 결과는 다음과 같습니다.

 

 

 그러면 첫 글자가 'A'나 'E'나 'a'나 'e'로 시작하지 않는 것들도 구할 수 있을까요? 네. in 앞에 not을 붙이면 됩니다. 그러면 _name의 첫 글자만 뽑아낸 것이 {'A', 'E', 'a', 'e'}에 속하는 원소 중 하나가 아니다. 라는 겁니다. 즉, 'A'나 'E'나 'a'나 'e'로 시작하지 않는다는 건데요.

 

 이 쿼리의 결과는 아래와 같습니다.

 

 

 중요한 것은, _name이 NULL인 것이 하나 빠졌다고 했는데요. NULL은 어느 값인지 모르기 때문에 그렇습니다. 이 값은 다룰 때 주의를 해야 합니다.

 

 


 이제, 어떤 걸 생각해 볼까요? 일단, 우리는 이 쿼리가 어떻게 수행되는지 생각해 볼 필요는 있어요.

 

 

 country에서 뽑는데 Name이 'South korea'이거나 'China'이거나 'Japan'인 경우를 가져오는 쿼리입니다.

 

 

 테이블에 인덱스를 찾아보니까, Code라는 컬럼에만 BTREE가 걸려 있습니다. 이것은 정렬된 구조를 유지하는 특수한 자료구조인데요. Name에 대해서는 걸려있지 않습니다. TreeMap을 생각해 보세요. 보통 이 친구들은 Key값에 대해서 정렬이 되어 있어요. Value 값에 대해서는 정렬이 되어 있지 않아요.

 

 그러면 Key값을 찾을 때 빨리 찾겠지만, V값은 전체 순회를 해야 하기 때문에, 매우 오래 걸릴 거에요. 사실, V를 key값으로 삼아서 다른 맵에 넣는 방법도 있기는 합니다. 그거랑 마찬가지 이치입니다.

 

 

 그렇기 때문에 Full Table Scan이 일어납니다.

 

 

 그런데 이 경우는 어떤가요? Code에 인덱스가 걸려 있었습니다. 그러면, Index를 탈 거에요.

 

 

 인덱스 값을 가지고 탐색을 하면 끝납니다. 그런가요? 'USA'이거나, 'JPN'이거나, 'RUS'이거나. 이 셋인데요. Code가 인덱스가 걸려있으니까, 처음에 'USA'가 어디 있는지 BTREE에서 찾고, 다음에 'JPN'이 어디있나 또 BTREE에서 찾고, 이런 식으로 하면 Full Table Scan 보다는 빨리 찾을 수 있을 거에요.

 

 

 그런데 이 경우는 이야기가 달라집니다. 이 때에는 인덱스로 걸려있기는 한데, index의 장점을 발휘하지는 못합니다. Java에는 Map 자료구조가 있어요. Key값이 3이거나, 5이거나, 10인 <K,V>쌍은 빠르게 찾을 수 있어요. 그런데, Key가 3이 아닌 <K,V>쌍을 찾으려면 어떻게 해야 하나요? 일일히 다 탐색을 해야 하지 않을까요? Map의 장점을 잘 활용하지 못하게 됩니다. 그것과 마찬가지 상황이라고 보시면 되겠습니다.