조금 신기한 현상을 봐서 정리해본다. 

# 테스트용 테이블 zipcode_01 생성 
mysql> create table zipcode_01 as select * from zipcode where 1=0;
Query OK, 0 rows affected (0.08 sec)
Records: 0  Duplicates: 0  Warnings: 0

# buildnum + zipcode 를 PK로 잡아준다. (결합인덱스)
mysql> alter table zipcode_01 add primary key (buildnum, zipcode);
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

# 테스트용 데이터 입력 
mysql> insert into zipcode_01 select * from zipcode order by buildnum, zipcode;
Query OK, 6348671 rows affected (4 min 21.79 sec)
Records: 6348671  Duplicates: 0  Warnings: 0

# zipcode_01, zipcode 테이블의 인덱스 정보 확인 
mysql> show index from zipcode_01;
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table      | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| zipcode_01 |          0 | PRIMARY  |            1 | buildnum    | A         |     6236954 |     NULL | NULL   |      | BTREE      |         |               |
| zipcode_01 |          0 | PRIMARY  |            2 | zipcode     | A         |     6236954 |     NULL | NULL   |      | BTREE      |         |               |
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.04 sec)

mysql> show index from zipcode;
+---------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table   | Non_unique | Key_name     | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| zipcode |          0 | PRIMARY      |            1 | seq         | A         |     6097975 |     NULL | NULL   |      | BTREE      |         |               |
| zipcode |          1 | idx1_zipcode |            1 | sido        | A         |        6667 |     NULL | NULL   | YES  | BTREE      |         |               |
| zipcode |          1 | idx1_zipcode |            2 | buildname   | A         |     1945822 |     NULL | NULL   | YES  | BTREE      |         |               |
+---------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.01 sec)

 

테스트용 데이터 고르기

# 아래의 데이터로 테스트를 진행한다. 
# zipcode : 06018, buildnum : 1168010700106590009000001
# zipcode : 07783, buildnum : 1150010300108490001023500
mysql> select zipcode, buildnum from zipcode where sido = '서울특별시' and  buildname like '혜성빌딩%';
+---------+---------------------------+
| zipcode | buildnum                  |
+---------+---------------------------+
| 06018   | 1168010700106590009000001 |
| 07783   | 1150010300108490001023500 |
...
19 rows in set (5.82 sec)

 

Select 문은 buildnum + zipcode PK 잘탄다. 

mysql> explain select * from zipcode_01 
    -> where zipcode in ('06018', '07783')
    ->   and buildnum in (select buildnum 
    ->                    from zipcode 
    ->                    where sido = '서울특별시' 
    ->                      and buildname like '혜성빌딩%');
+----+-------------+------------+-------+--------------+---------+--------------------------+------+----------+-----------------------------------------------------+
| id | select_type | table      | type  | key          | key_len | ref                      | rows | filtered | Extra                                               |
+----+-------------+------------+-------+--------------+---------+--------------------------+------+----------+-----------------------------------------------------+
|  1 | SIMPLE      | zipcode    | range | idx1_zipcode | 386     | NULL                     |   19 |   100.00 | Using index condition; Using where; Start temporary |
|  1 | SIMPLE      | zipcode_01 | ref   | PRIMARY      | 102     | zipcode.zipcode.buildnum |    1 |    20.00 | Using where; End temporary                          |
+----+-------------+------------+-------+--------------+---------+--------------------------+------+----------+-----------------------------------------------------+

 

자 그럼 Delete는? 인덱스 안탄다.. key 도 없고 type ALL 이다. 

mysql> explain delete from zipcode_01 
    -> where zipcode in ('06018', '07783')
    ->   and buildnum in (select buildnum 
    ->                    from zipcode 
    ->                    where sido = '서울특별시' 
    ->                      and buildname like '혜성빌딩%');
+----+--------------------+------------+-------+--------------+---------+------+---------+----------+------------------------------------+
| id | select_type        | table      | type  | key          | key_len | ref  | rows    | filtered | Extra                              |
+----+--------------------+------------+-------+--------------+---------+------+---------+----------+------------------------------------+
|  1 | DELETE             | zipcode_01 | ALL   | NULL         | NULL    | NULL | 6236954 |   100.00 | Using where                        |
|  2 | DEPENDENT SUBQUERY | zipcode    | range | idx1_zipcode | 386     | NULL |      19 |    10.00 | Using index condition; Using where |
+----+--------------------+------------+-------+--------------+---------+------+---------+----------+------------------------------------+

 

물론 아래처럼 where 절에 in 절을 join 으로 바꾸거나 buildnum 을 직접 넣어주면 인덱스 잘탄다. 

mysql> explain delete from zipcode_01 
    -> where zipcode in ('06018', '07783')
    ->   and buildnum in ('1168010700106590009000001','1150010300108490001023500');
+----+-------------+------------+-------+---------+---------+-------------+------+----------+-------------+
| id | select_type | table      | type  | key     | key_len | ref         | rows | filtered | Extra       |
+----+-------------+------------+-------+---------+---------+-------------+------+----------+-------------+
|  1 | DELETE      | zipcode_01 | range | PRIMARY | 124     | const,const |    4 |   100.00 | Using where |
+----+-------------+------------+-------+---------+---------+-------------+------+----------+-------------+

mysql> explain delete a 
    -> from zipcode_01 a 
    -> inner join zipcode b on a.zipcode = b.zipcode and a.buildnum = b.buildnum 
    -> where b.sido = '서울특별시' and b.buildname like '혜성빌딩%'
    ->  and a.zipcode in ('06018', '07783');
+----+-------------+-------+--------+--------------+---------+--------------------------------------+------+----------+-------------+
| id | select_type | table | type   | key          | key_len | ref                                  | rows | filtered | Extra       |
+----+-------------+-------+--------+--------------+---------+--------------------------------------+------+----------+-------------+
|  1 | SIMPLE      | b     | range  | idx1_zipcode | 386     | NULL                                 |   19 |   100.00 | Using where |
|  1 | DELETE      | a     | eq_ref | PRIMARY      | 124     | zipcode.b.buildnum,zipcode.b.zipcode |    1 |   100.00 | NULL        |
+----+-------------+-------+--------+--------------+---------+--------------------------------------+------+----------+-------------+

 

혹시나 하는 생각에 buildnum + zipcode의 반대인 zipcode + buildnum 결합인덱스를 생성하고 다시 쿼리!

zipcode + buildnum 결합인덱스 잘탄다.

Delete 시에는 결합인덱스의 첫번째 컬럼을 조회하는 IN 절에 서브 쿼리가 들어가 있는 경우는 인덱스를 안타는구나..

mysql> explain delete from zipcode_01 
    -> where zipcode in ('06018', '07783')
    ->   and buildnum in (select buildnum 
    ->                    from zipcode 
    ->                    where sido = '서울특별시' 
    ->                      and buildname like '혜성빌딩%');
+----+--------------------+------------+-------+----------------+---------+-------+------+----------+------------------------------------+
| id | select_type        | table      | type  | key            | key_len | ref   | rows | filtered | Extra                              |
+----+--------------------+------------+-------+----------------+---------+-------+------+----------+------------------------------------+
|  1 | DELETE             | zipcode_01 | range | idx_zipcode_01 | 22      | const |  351 |   100.00 | Using where                        |
|  2 | DEPENDENT SUBQUERY | zipcode    | range | idx1_zipcode   | 386     | NULL  |   19 |    10.00 | Using index condition; Using where |
+----+--------------------+------------+-------+----------------+---------+-------+------+----------+------------------------------------+

 

여기서 또 하나 궁금해지는것 그렇다면 zipcode + buildnum 결합인덱스를 삭제하고 buildnum + zipcode 결합인덱스만있는 상태에서 쿼리를 고쳐서 하면? 인덱스 잘탄다. 

# idx_zipcode_01 (zipcode + buildnum) 인덱스 삭제 
mysql> alter table zipcode_01 drop index idx_zipcode_01 ;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> explain delete from zipcode_01 
    -> where buildnum in ('1168010700106590009000001','1150010300108490001023500')
    ->   and zipcode in (select zipcode 
    ->                    from zipcode 
    ->                    where sido = '서울특별시' 
    ->                      and buildname like '혜성빌딩%');
+----+--------------------+------------+-------+--------------+---------+-------+------+----------+------------------------------------+
| id | select_type        | table      | type  | key          | key_len | ref   | rows | filtered | Extra                              |
+----+--------------------+------------+-------+--------------+---------+-------+------+----------+------------------------------------+
|  1 | DELETE             | zipcode_01 | range | PRIMARY      | 102     | const |    2 |   100.00 | Using where                        |
|  2 | DEPENDENT SUBQUERY | zipcode    | range | idx1_zipcode | 386     | NULL  |   19 |    10.00 | Using index condition; Using where |
+----+--------------------+------------+-------+--------------+---------+-------+------+----------+------------------------------------+

 

그렇다면 Update는 어떨까? 

동일하다!

mysql> explain update zipcode_01 
    -> set sido = '강남시'
    -> where zipcode in ('06018', '07783')
    ->   and buildnum in (select buildnum 
    ->                    from zipcode 
    ->                    where sido = '서울특별시' 
    ->                      and buildname like '혜성빌딩%');
+----+--------------------+------------+-------+--------------+---------+------+---------+----------+------------------------------------+
| id | select_type        | table      | type  | key          | key_len | ref  | rows    | filtered | Extra                              |
+----+--------------------+------------+-------+--------------+---------+------+---------+----------+------------------------------------+
|  1 | UPDATE             | zipcode_01 | index | PRIMARY      | 124     | NULL | 6236954 |   100.00 | Using where                        |
|  2 | DEPENDENT SUBQUERY | zipcode    | range | idx1_zipcode | 386     | NULL |      19 |    10.00 | Using index condition; Using where |
+----+--------------------+------------+-------+--------------+---------+------+---------+----------+------------------------------------+

mysql> alter table zipcode_01 add index idx_zipcode_01 (zipcode, buildnum);
Query OK, 0 rows affected (41.36 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> explain update zipcode_01 
    -> set sido = '강남시'
    -> where zipcode in ('06018', '07783')
    ->   and buildnum in (select buildnum 
    ->                    from zipcode 
    ->                    where sido = '서울특별시' 
    ->                      and buildname like '혜성빌딩%');
+----+--------------------+------------+-------+----------------+---------+-------+------+----------+------------------------------------+
| id | select_type        | table      | type  | key            | key_len | ref   | rows | filtered | Extra                              |
+----+--------------------+------------+-------+----------------+---------+-------+------+----------+------------------------------------+
|  1 | UPDATE             | zipcode_01 | range | idx_zipcode_01 | 22      | const |  351 |   100.00 | Using where                        |
|  2 | DEPENDENT SUBQUERY | zipcode    | range | idx1_zipcode   | 386     | NULL  |   19 |    10.00 | Using index condition; Using where |
+----+--------------------+------------+-------+----------------+---------+-------+------+----------+------------------------------------+

'MySQL' 카테고리의 다른 글

binlog format  (0) 2021.05.15
인덱스 최대 크기  (0) 2021.05.13
MySQL 포퍼먼스 튜닝  (0) 2021.05.12
MySQL 5.7 Virtual Columns  (0) 2021.04.27
MySQL 5.6 -> 5.7 병렬복제  (0) 2021.04.27

+ Recent posts