인덱스 컬럼 사이즈와 SELECT 속도에 대해서 테스트를 진행해보았습니다.
인덱스 컬럼 사이즈가 큰 경우에는 Page에 저장되는 인덱스정보개수가 적어지기 때문에, 페이지테이블에 대한 접근이 증가하기 때문에, 성능상 좋지 않다고 말씀드렸었습니다.
실제로 인덱스로 사용하는 컬럼의 사이즈가 큰 경우에 SELECT 조회에 어떤 영향을 주는지 확인해보겠습니다.
테스트를 진행하는 테이블의 스키마입니다.
mysql> desc employees;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| email | varchar(50) | NO | | NULL | |
| first_name | varchar(14) | NO | | NULL | |
| last_name | varchar(16) | NO | | NULL | |
| birth_date | date | NO | | NULL | |
| mobile | varchar(30) | NO | MUL | NULL | |
| gender | varchar(10) | NO | MUL | NULL | |
| zipcode | varchar(15) | NO | | NULL | |
| address | varchar(200) | NO | | NULL | |
| hire_date | date | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
10 rows in set (0.20 sec)
varchar 데이터타입을 많이 사용하고 있습니다.
먼저, varchar 데이터타입을 사용하는 컬럼의 데이터 저장사이즈를 한번 체크해보겠습니다.
mysql> SELECT AVG(LENGTH(email)),AVG(LENGTH(first_name)), AVG(LENGTH(last_name)), AVG(LENGTH(mobile)), AVG(LENGTH(gender)), AVG(LENGTH(zipcode)), AVG(LENGTH(address)) from employees;
+--------------------+-------------------------+------------------------+---------------------+---------------------+----------------------+----------------------+
| AVG(LENGTH(email)) | AVG(LENGTH(first_name)) | AVG(LENGTH(last_name)) | AVG(LENGTH(mobile)) | AVG(LENGTH(gender)) | AVG(LENGTH(zipcode)) | AVG(LENGTH(address)) |
+--------------------+-------------------------+------------------------+---------------------+---------------------+----------------------+----------------------+
| 22.9256 | 5.9710 | 6.5479 | 16.5999 | 1.0000 | 7.5003 | 11.5273 |
+--------------------+-------------------------+------------------------+---------------------+---------------------+----------------------+----------------------+
1 row in set (1 min 20.44 sec)
먼저 데이터 사이즈가 큰 컬럼들을 이용해서 인덱스를 생성해보겠습니다.
CREATE INDEX IDX_LARGE_COLUMNS ON employees (email, mobile, address);
인덱스로 사용한 총 컬럼의 사이즈 총합은 row당 51.03(22.92 + 16.59 + 11.52)바이트입니다.
데이터 사이즈가 작은 컬럼들을 이용해서 인덱스를 생성해보겠습니다.
CREATE INDEX IDX_SMALL_COLUMNS ON employees (last_name, zipcode, hire_date);
인덱스로 사용한 총 컬럼의 사이즈 총합은 row당 17.04(6.54 + 7.50 + 3)바이트입니다.
(* hire_date는 date타입인데, 3바이트를 사용합니다)
위에서 생성한 2개의 인덱스를 이용해서 쿼리를 20회 실행하였습니다.
select SQL_NO_CACHE * from employees use index (IDX_LARGE_COLUMNS) where email in ('iuhahhahiadphioa@gmail.com', 'iJHGFBSDLhioa@gmail.com', 'iuIUHFGD8923phioa@gmail.com', 'iFIULKB2dphioa@gmail.com', 'iuGFSOUNPa@gmail.com')
AND mobile in ('02314090923', '098431525', '09419015', '023140', '094531525')
AND address in ('Seoul', 'Newyork', 'Pusan', 'Beijing', 'Singapore' );
select SQL_NO_CACHE * from employees use index (IDX_SMALL_COLUMNS) where
last_name in ('Steve', 'Tom', 'Zeus', 'Marie', 'Steve')
AND zipcode in ('90345-23', '9483626', '09523901', '124113', '34215-23')
AND hire_date in ( DATE_FORMAT('20210310', 'YYYYMMDD'), DATE_FORMAT('20110310', 'YYYYMMDD'), DATE_FORMAT('20190110', 'YYYYMMDD'), DATE_FORMAT('20180210', 'YYYYMMDD'), DATE_FORMAT('20150110', 'YYYYMMDD'));
20회 조회한 결과입니다.
IDX_LARGE_COLUMNS | IDX_SMALL_COLUMNS | |
1회 | 187ms | 203ms |
2회 | 203ms | 188ms |
3회 | 203ms | 187ms |
4회 | 203ms | 188ms |
5회 | 203ms | 187ms |
6회 | 188ms | 203ms |
7회 | 187ms | 188ms |
8회 | 188ms | 188ms |
9회 | 188ms | 203ms |
10회 | 203ms | 187ms |
11회 | 203ms | 188ms |
12회 | 203ms | 203ms |
13회 | 203ms | 203ms |
14회 | 204ms | 187ms |
15회 | 203ms | 203ms |
16회 | 188ms | 203ms |
17회 | 188ms | 203ms |
18회 | 203ms | 204ms |
19회 | 187ms | 204ms |
20회 | 203ms | 203ms |
평균 | 196.9ms | 196.15ms |
IDX_LARGE_COLUMNS가 IDX_SMALL_COLUMNS보다
인덱스 컬럼의 사이즈 총합이 3배 가까이 되지만, 실제 검색쿼리의 시간에 큰 차이는 없었습니다.
SELECT조회시에 페이지테이블에 접근하는 횟수가 많아지고, 그로 인해 SELECT 조회 속도에 차이가 생길 것으로 예상했습니다만, 결과는 예상 밖이었습니다.
캐시를 사용하지 않게 하기 위해서 SQL_NO_CACHE 힌트를 주었으나, 결과가 예상밖이어서
이번에는 query_cache_type을 0으로 설정후에 다시 테스트를 진행해 보았습니다.
IDX_LARGE_COLUMNS | IDX_SMALL_COLUMNS | |
1회 | 188 | 188 |
2회 | 188 | 203 |
3회 | 188 | 188 |
4회 | 203 | 187 |
5회 | 187 | 204 |
6회 | 188 | 187 |
7회 | 203 | 203 |
8회 | 187 | 188 |
9회 | 188 | 203 |
10회 | 187 | 203 |
11회 | 188 | 187 |
12회 | 188 | 203 |
13회 | 188 | 203 |
14회 | 188 | 188 |
15회 | 203 | 188 |
16회 | 187 | 188 |
17회 | 203 | 204 |
18회 | 188 | 188 |
19회 | 187 | 187 |
20회 | 188 | 187 |
평균 | 190.75 | 193.85 |
my.cnf의 query_cache_type 설정을 변경해도 비슷한 결과가 나왔습니다.
EPXLAIN결과를 다시 살펴 보았습니다.
mysql> explain select SQL_NO_CACHE * from employees use index (IDX_LARGE_COLUMNS) where email in ('iuhahhahiadphioa@gmail.com', 'iJHGFBSDLhioa@gmail.com', 'iuIUHFGD8923phioa@gmail.com', 'iFIULKB2dphioa@gmail.com', 'iuGFSOUNPa@gmail.com')
-> AND mobile in ('02314090923', '098431525', '09419015', '023140', '094531525')
-> AND address in ('Seoul', 'Newyork', 'Pusan', 'Beijing', 'Singapore' );
+----+-------------+-----------+------------+-------+-------------------+-------------------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+-------------------+-------------------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | employees | NULL | range | IDX_LARGE_COLUMNS | IDX_LARGE_COLUMNS | 846 | NULL | 125 | 100.00 | Using index condition |
+----+-------------+-----------+------------+-------+-------------------+-------------------+---------+------+------+----------+-----------------------+
1 row in set, 2 warnings (0.19 sec)
mysql> explain select SQL_NO_CACHE * from employees use index (IDX_SMALL_COLUMNS) where
-> last_name in ('Steve', 'Tom', 'Zeus', 'Marie', 'Steve')
-> AND zipcode in ('90345-23', '9483626', '09523901', '124113', '34215-23')
-> AND hire_date in ( DATE_FORMAT('20210310', 'YYYYMMDD'), DATE_FORMAT('20110310', 'YYYYMMDD'), DATE_FORMAT('20190110', 'YYYYMMDD'), DATE_FORMAT('20180210', 'YYYYMMDD'), DATE_FORMAT('20150110', 'YYYYMMDD'));
+----+-------------+-----------+------------+-------+-------------------+-------------------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+-------------------+-------------------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | employees | NULL | range | IDX_SMALL_COLUMNS | IDX_SMALL_COLUMNS | 97 | NULL | 20 | 50.00 | Using index condition |
+----+-------------+-----------+------------+-------+-------------------+-------------------+---------+------+------+----------+-----------------------+
IDX_LARGE_COLUMNS를 이용하는 경우의 profile정보를 확인하였습니다.
show profile;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000080 |
| checking permissions | 0.000005 |
| Opening tables | 0.000049 |
| init | 0.000033 |
| System lock | 0.000004 |
| optimizing | 0.000008 |
| statistics | 0.000899 |
| preparing | 0.000015 |
| executing | 0.000002 |
| Sending data | 0.000387 |
| end | 0.000003 |
| query end | 0.000009 |
| closing tables | 0.000005 |
| freeing items | 0.000047 |
| cleaning up | 0.000002 |
+----------------------+----------+
15 rows in set, 1 warning (0.19 sec)
IDX_SMALL_COLUMNS를 이용하는 경우의 profile정보를 확인하였습니다.
mysql> show profile;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000091 |
| checking permissions | 0.000005 |
| Opening tables | 0.000015 |
| init | 0.000043 |
| System lock | 0.000005 |
| optimizing | 0.000009 |
| statistics | 0.000193 |
| preparing | 0.000015 |
| executing | 0.000002 |
| Sending data | 0.000074 |
| end | 0.000002 |
| query end | 0.000005 |
| closing tables | 0.000005 |
| freeing items | 0.000051 |
| cleaning up | 0.000002 |
+----------------------+----------+
15 rows in set, 1 warning (0.19 sec)
실행속도를 확인 하는 방법을 MySQL의 workbench를 이용해서 아래 정보를 이용해서 측정하였는데, 아무래도 측정방법이 잘못 된거 같습니다. 더 정확한 측정방법에 대해서 다음에 다시 정리해보겠습니다.
'MySQL > Index' 카테고리의 다른 글
MySQL Index (2) 기본 기능 (2) | 2021.10.05 |
---|---|
MySQL Index (4) 커버링 인덱스 (0) | 2021.10.04 |
MySQL Index (1) 개요 (0) | 2021.10.01 |