들어가며
다른 RDBMS는 모르겠지만 MySQL에서 IN subquery의 성능은 별로 좋지를 못하다. 본 글에서는 IN Subquery의 작동 방식을 살펴볼 것이다.
Data는 TPC-H 벤치마크 데이터를 이용하여 실험하였다. TPC-H 데이터를 MySQL에 Loading하는 것은 필자가 작성한 글을 보기 바란다.
본 글은 MySQL 5.5를 기준으로 작성되었다. MySQL 5.6에서는 subquery materialization을 이용하여 IN subquery의 성능이 향상되었다. MySQL 5.6의 IN () 성능 측정 결과는 다른 포스트에 정리할 예정이다.
IN subquery는 속도가 느리다
다음과 같이 30만명의 고객(customer)와 300만개의 주문(orders)가 존재한다.
mysql> SELECT COUNT(*) FROM customer;
+----------+
| COUNT(*) |
+----------+
| 300000 |
+----------+
1 row in set (0.00 sec)
mysql> SELECT COUNT(*) FROM orders;
+----------+
| COUNT(*) |
+----------+
| 3000000 |
+----------+
1 row in set (0.46 sec)
우선 2명의 고객 정보를 조회했다.
mysql> SELECT c_custkey FROM customer LIMIT 2;
+-----------+
| c_custkey |
+-----------+
| 29 |
| 48 |
+-----------+
2 rows in set (0.00 sec)
이들이 주문한 주문 정보를 조회하는 것은 다음과 같이 조회하면 된다. o_custkey가 INDEX로 걸려있기 때문에 수행 속도가 무척 빠르다.
mysql> SELECT SQL_NO_CACHE o_orderkey FROM orders WHERE o_custkey IN (29, 48);
+------------+
| o_orderkey |
+------------+
| 1572644 |
| 2773829 |
| 3440902 |
| 5779717 |
| 6144551 |
| 9493348 |
| 9974083 |
+------------+
7 rows in set (0.00 sec)
하지만, 쿼리를 다음과 같이 변경하면 동일한 결과가 출력되지만 3.12초나 걸린다!
mysql> SELECT SQL_NO_CACHE o_orderkey
-> FROM orders
-> WHERE o_custkey IN
(SELECT c_custkey FROM customer WHERE c_custkey IN (29, 48));
+------------+
| o_orderkey |
+------------+
| 1572644 |
| 2773829 |
| 3440902 |
| 5779717 |
| 6144551 |
| 9493348 |
| 9974083 |
+------------+
7 rows in set (3.12 sec)
어떻게 된 것일까?
출처: http://jason-heo.github.io/mysql/2014/05/22/avoid-mysql-in.html