Publicidad

MySQL_SQL_Tunning_v0.1.3.docx

NeoClova
NeoClova
22 de Mar de 2022
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
Publicidad
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
Publicidad
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
Publicidad
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
Publicidad
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
Publicidad
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
Publicidad
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
MySQL_SQL_Tunning_v0.1.3.docx
Próximo SlideShare
MySQL_MariaDB-성능개선-202201.pptxMySQL_MariaDB-성능개선-202201.pptx
Cargando en ... 3
1 de 33
Publicidad

Más contenido relacionado

Presentaciones para ti(20)

Publicidad

Último(20)

MySQL_SQL_Tunning_v0.1.3.docx

  1. 1 MySQL/MariaDB SQL Tunning (For Beginner) ㈜ 네오클로바 DB 기술지원팀
  2. 2
  3. 3 목차 1. 개요 2. DBMS Tunning 을 위해 알아야 할것들. 2-1. DBMS 성능개선 (모델링 > 시스템 > SQL) 2-2. MySQL/MariaDB Architecture 2-3. InnoDB 구조 2-4. Primary Key 와 Secondary Key 2-5. Join 방식 2-6. Limit 3. SQL 실행계획 3-1. 쿼리실행과정 3-2. 통계정보 3-3. 옵티마이저 3-4. Explain 3-5. Profiling 4. Explain 파해치기 5. SQL 을 위한 인덱스전략 6. SQL 작성가이드 7. 사례로보는 SQL Tunning - 별첨
  4. 4 1. 개요 오픈소스의 관계형 데이터베이스 관리 시스템(RDBMS)에서 가장 많이 쓰이는 소프트웨어가 MySQL 과 MariaDB 이다. MySQL 은 MySQL AB 가 관리/지원하다 2008 년 썬마이로그시스템즈에 인수되었으며, 2010 년 오라클이 썬마이크로시스템즈를 인수하면서 현재 오라클이 MySQL 소유권을 가지고 있습니다. MariaDB 는 MySQL 과 동일한 소스코드를 기반으로 한 GPL2 라이선스를 따른다. 썬이 오르클에 인수되면서, 2009 년 Michael Monty Widenius 가 썬을 떠나서 “Monty Program AB”사를 창립합니다. 2012 년 비영리단체인 “Maria DB Foundation”을 설립해서 MariaDB 를 GPL 라이선스로 배포하기 시작했다. 이후 SkySQL 이 “Monty Program AB”를 합병하여 2014 년 “MariaDB Corporation”으로 회사명을 변경하여 오늘에 이르고 있습니다. “MariaDB Foundation”(www.mariadb.org)은 비영리단체로 GPL 라이선스를 소유하고 있으며, “MariaDB Corporation”(www.mariadb.com)은 영리단체입니다.
  5. 5 MySQL fork - MariaDB - Percona Server - Drizzle - WebScaleSQL - Facebook - Twitter - AliSQL - 등등등 2015’
  6. 6 2. DBMS Tunning 을 위해 알아야 할 것들 2.1. DBMS 의 성능개선 데이터베이스의 성능개선은 DBMS 자체, Application, OS 조정등을 통하여 최적의 자원으로 최적의 성능(시간/응답속도)를 얻을 수 있도록 개선하는 작업을 의미합니다. 그렇다면 성능개선의 관점에서 보면 다음과 같은 목적을 가질 수 있다. 관점 목적 내용 대기 분석 (Wait time) 대기시간 최소화 - 동시 세션이 데이터베이스에 접근 할 경우 - DB 자원을 취득하기 위해 대기하는 시간 분석 응답 시간 (Response Time) 응답시간 최소화 - SQL 실행 후 결과가 피드백 되기까지의 시간 분석 비율 분석 (Hit Ratio) Hit Rate 최대화 - 데이터베이스의 버퍼 캐쉬의 히트 율 분석, - DISK IO 를 최소화 하도록 메모리 히트 율 향상 이러한 성능개선의 목적을 달성하기 위해서는 크게 세가지의 개선분야(요소)로 구분할 수 있다. 개선요소 설 명 사 례 DB 설계 (모델링관점) - 데이터베이스 설계 단계에서 성능을 고려하여 설계 - 데이터 모델링 (논리모델) - 인덱스설계, 데이터파일, 테이블, 스페이스 설계(물리모델) - 데이터베이스 용량 산정 - 정규화/반정규화 - 분산파일배치 DBMS 환경 (환경 측면) - 성능을 고려하여 메모리나 블록 크기 등을 지정 - CPU, 메모리 I/O 에 관한 관점 - Buffer, Cache 크기 - 고성능 Disk OS, HW, N/W SQL 요소 (응용프로그램 측면) - SQL 작성 시 성능 고려 - join, Indexing, SQL Execution Plan - Hash / Join - Hint 성능에 영향을 미치는 세가지 개선요소들 중에서 어느 것 하나 무시할 수 없지만, 우선순위로 보자면 DB 모델링 > DBMS 환경구성 > Application SQL 작성 순서로 보는 게 일반적이다. 다음은 각 요소 별 주요 튜닝항목들이다 [DB 설계 튜닝] 구분 내용 테이블의 분할/통합 - 논리적으로는 통합된 단일 테이블이지만 DBMS 가 지원하는 파티션기능 적용함으로써 액세스 효율화로 DB I/O 를 최적화 할 수 있음 - - DBMS 에 따라 파티션기능이 제약되는 경우에는 테이블의 수평분할 고려 - 액세스 패턴에 따라 단일 테이블을 1:1 로 수직분할을 고려할 수 있음
  7. 7 식별자 지정 - 본질 식별자와 인조식별자의 선택에 따라 정보의 상속과 단절에 영향을 줄 수 있음 효율적인 인덱스 전략 - 최소한의 인덱스로 최대의 효과를 얻을 수 있는 최적의 인덱스 구조 수립 - 인덱스 분포도 15% 이하 유용 유도(15% 이상이면 Full Scan 유리) 적절한 데이터타입 선택 - 조인 시 연결되는 컬럼의 데이터 타입이 다른 경우 내부적인 변형에 의해 인덱스가 있음에도 불구하고 활용을 못해 조인순서나 조인방식을 달리 선택하는 비효율 발생 할 수 있음 [DBMS 환경 튜닝] 구분 내용 CPU 튜닝 - Peak Time 시에 60~70%의 사용량 유지 권고 - CPU 증설 또는 CPU 과다 점유하는 프로세스를 찾아서 해결 Memory 튜닝 - DBMS 의 사용 메모리의 최적화 필요 - 업무를 가능하게 하기 위한 충분한 메모리 확보 - DBMS 메모리 + Session 메모리 Disk I/O 튜닝 - I/O 를 분산시킬 수 있도록 데이터 파일의 재배치 - Raid 를 이용-> I/O 가 많이 일어나는 것은 Raid 1/0 에 배치 Network 튜닝 - Ping, Ftp 를 이용하여 응답시간 분석 [SQL 튜닝] 구분 내용 옵티마이저에 대한 이해기반 SQL 작성 - RBO (Rule Based Optimizer): 통계정보가 없는 상태에서 미리 정해진 Rule 에 따라 실행계획 수립 - CBO (Cost Based Optimizer): 통계정보로부터 모든 Access Path 를 고려하여 실행계획 수립 - 옵티마이저가 선택한 실행계획을 확인하고 최적화된 실행계획 수립이 이루어지도록 Factor 부여 힌트사용 - 옵티마이저가 항상 최적화된 실행계획을 수립하는 것은 아니므로 힌트를 사용하여 원하는 실행계획으로 유도 USE {INDEX|KEY} [FOR {JOIN|ORDER BY|GROUP BY}] ([index_list]) IGNORE {INDEX|KEY} [FOR {JOIN|ORDER BY|GROUP BY}] (index_list) FORCE {INDEX|KEY} [FOR {JOIN|ORDER BY|GROUP BY}] (index_list) 부분범위 처리 - 조건을 만족하는 전체집합이 아닌 일부분만 액세스하고도 결과를 리턴 할 수 있도록 하여 온라인 프로그램에서 응답시간(Response Time)을 최소화 할 수 있음 인덱스 활용 - 인덱스가 있음에도 불구하고 SQL 을 잘못 기술함으로써 무용지물로 만드는 오류 제거
  8. 8 조인방식/ 조인순서 - 동일한 SQL 문이라도 조인방식과 조인순서에 따라 처리속도는 매우 큰 차이를 가져올 수 있으므로 작성한 SQL 이 어떤 실행계획으로 수립되는 지 반드시 확인 후 조정 다중처리 (Array Processing) - 배치작업의 경우 한번의 DBMS 호출로 여러 건을 동시에 처리할 수 있는 다중처리 활용 병렬쿼리 (Parallel Query) - 배치작업의 경우 하나의 SQL 을 여러 개의 CPU 가 병렬로 분할 처리하게 함으로써 처리속도 향상 가져옴(단 Parallel 지원 DBMS) Prepared SQL 사용 - 조건절에 입력된 값을 먼저 Binding 한 후 실행계획을 수립하는 Dynamic SQL 은 파싱 부하가 커지므로 입력 값을 Binding 하기 전에 실행계획을 수립하는 Static SQL 을 가급적 사용하도록 함. 그러나 DBMS 마다 차이가 존재함. MySQL 은 Prepared(보안측면 효과) 권고 결국 ➔ 얼마나 적은 CPU, Memory, Disk IO 를 통해서 동일한 결과를 가져올 것인가? ➔ 얼마나 빨리 동일한 결과를 가져올 것인가? ➔ 대부분 Disk IO 부하에서 병목현상이 발생함으로 적은 Page Read IO 가 우선적으로 이해.
  9. 9 2.2. MySQL / MariaDB Architecture 1. MySQL Architecture 2. MariaDB Architecture
  10. 10 2.3. INNODB 구조 - System Tablespace(space ID=0), Innodb Tables-per table(space ID>0) : 32bit space ID 할당 - ibdata 정보를 확인할 때 innochecksum utility 확인 (offline 수행) - [root@VM1 ~]# ./innochecksum --page-type-summary /usr/local/mysql/data/ibdata1 - File::/usr/local/mysql/data/ibdata1 - ================PAGE TYPE SUMMARY============== - #PAGE_COUNT PAGE_TYPE - =============================================== - 39 Index page - 427 Undo log page - 6 Inode page - 0 Insert buffer free list page - 5793 Freshly allocated page - 1 Insert buffer bitmap - 131 System page - 1 Transaction system page - 2 File Space Header - 0 Extent descriptor page - 0 BLOB page - 0 Compressed BLOB page - 0 Other type of page - =============================================== - Additional information: - Undo page type: 128 insert, 299 update, 0 other - Undo page state: 0 active, 224 cached, 0 to_free, 1 to_purge, 0 prepared, 202 other 1. Tablespace - Row > Page(16K) > Extent(64 pages) > Segment > Tablespace 구조(디렉토리= 데이터베이스) - .frm = 테이블구조(MyISAM 과 동일) - .ibd = 테이블 Data Internal Data Dictionary Replication Info Insert Buffer, DoubleWirte Buffer Undo Logs System Tablespace ibdata[n] files Innodb_file_per_tabl e .frm file .ibd file InnoDB Tables ---[n] .frm+.idb (per tables) DM Saved Data
  11. 11 2. Pages (16Kbyte, 2^32 * 16K=64TB) – Double linked list 구조 FIL Header(38) Row Datas (16,338) … Row Offset Array FIL Trailer(8) 3. File per table 시 ibd 파일 구조 4. Index Pages 자세한 사항은 아래를 참고하세요. 참고 : https://blog.jcole.us/2013/01/03/the-basics-of-innodb-space-file-layout/ Checksum(4) Offset(Page Number)(4) Previous Page(4) Next Page(4) LSN for last page modification(4) Page Type(2) Flush LSN(0 except space 0 page 0)(8) Space ID(4) Old-style Checksum(4) Low 32bits of LSN(4)
  12. 12 2.4. Primary Key 와 Secondary Key MySQL/MariaDB 는 PK 를 생성하지 않아도 내부적으로 반드시 6bytes 의 ROWID 값에 대한 더미용 PK 를 생성한다. 이 값은 Secondary Index 에 포함되어 Lookup 시 활용한다. 1. Primary Key or Internal 컬럼 ROW_ID (6byte) 2. Secondary Key Contain Primary Key 확인) create table t (id int primary key, nm varchar(10)); create index t_idx1 on t(nm); create index t_idx1 on t(nm, id); 두 인덱스의 차이? 결과는?
  13. 13 2.5. Join - 모든 SQL 처리는 싱글 코어처리(병렬처리 안됨) - 오직 Nested Loop Join 만으로 join 처리 - 연결고리가 되는 컬럼을 사용하여 바깥쪽 테이블(driving table)과 안쪽 테이블(driven table) 접근. - 바깥쪽 테이블의 한 row 의 컬럼을 읽고 조인되는 컬럼값을 통해 안쪽 테이블의 한 row 에 대한 조인 컬럼에 대한 결과값을 만들고, 다시 바깥쪽 테이블의 다음의 한 Row 를 읽고 연결된 안쪽테이블의 컬럼을 읽어갑니다. 이렇게 바깥 테이블에 더 이상 남은 행이 없을 때 까지 연산을 수행합니다. - 단 어떤 테이블을 먼저 읽을지에 대한 판단은 옵티마이저가 결정할 문제이며, 순차적 조인 힌트인 STRAIGHT_JOIN 통해서 사용자가 작성한 테이블이의 순서대로 JOIN 을 수행합니다. SELECT STRAIGHT_JOIN COUNTRY.COUNTRY_NAME ,CITY.CITY_NAME FROM COUNTRY INNER JOIN CITY ON CITY.COUNTRY_NAME = COUNTRY.COUNTRY_NAME WHERE 1=1; // COUNTRY >> CITY 이는 Oracle 의 ORDERED 와 동일하게 작동하는 HINT 이다.(SELECT /*+ORDERED */ … )
  14. 14 2-6. Limit 1. 한 테이블의 최대 컬럼 수 ? - MySQL 5.6.9 이전 – 1000 개 - 이후는 1017 개까지 (5.7 상의 가상컬럼 포함) 2. 한 테이블의 최대 인덱스 수? - 1 개 Primary Index + 64 개 Secondary Index = 최대 65 개 가능 그럼 MSSQL 은? 오라클은? 3. 컬럼의 인덱스 최대 키 길이(Bytes)는? - 기본 767byte - innodb_large_prefix=1 인 경우 3072 Byte 까지 지원 - row_format=DYNAMIC / COMPRESSED - 멀티컬럼의 경우는 전체 키조합 길이도 3072byte 까지 지원. - innodb_page_size=16K 면 3072byte, 8K 면 1536byte, 4K 면 768byte 로 변경됨. (MySQL 5.7.6 부터 innodb_page_size 변경가능) 주의) master / slave 동일하게 설정. 4. 한 Row 의 최대 컬럼 합 Byte 는? - 65,535byte 5. 단일 Tablespace 의 최대크기? - 64TB 6. 최대 Undo(데이터 변경 trx) 가능 Transaction 수? - undo log file 은 최대 128 개, 한 개 파일당 1023 trx 지원 : 128*1023 개 - 임시테이블 사용여부에 따라 다름. 참고: http://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html
  15. 15 3. SQL 실행계획 3.1. 쿼리 실행과정 - Query Cache : 사용 설정 시 캐시에 저장데이터 있으면 바로 결과 반환, 없으면 다음. - Parser : 쿼리를 토큰(parse tree)으로 분리해서 SQL 엔진 인식가능형태 변환. Syntax Error 확인. - Preprocesser : 쿼리에 구조적 문제없는지 체크. 객체 존재여부 권한확인 Filtering. - Optimizer : 쿼리변환, 최소 Cost, 실행계획 개선작업 수행 후 Query Execution Plan 생성. - Query Execution Engine : plan 순서대로 Storage Engine 에게 API Calls 수행함. (ex: innodb 에게 tmp tbl 만들라, where 조건수행후 읽어와라, 저장하라, 최종 set 생성 등) 결국 실행엔진에서 비효율발생 가능성이 있음. - Storage Engine : 실행엔진이 시키는 일(API Call)을 수행.
  16. 16 3.2. 통계정보 MySQL/MariaDB 에서는 CBO 기반 옵티마이저의 성능을 향상시키기 위해서 통계정보를 활용한다. 그러나 MySQL 의 통계정보에 대하여 몇가지 알아야 할 사항이 있다. MySQL 5.5 이하 버전에서는 Cardinality 정보만 관리하며, 타 DBMS 와 다르게 다양한 이벤트를 통해서 상당히 동적으로 통계정보가 변경됩니다. Cardinality 는 인덱스 컬럼 값의 Unique 값 수를 의미합니다. 유사한 정보로서 Histogram 은 인덱스 존재여부와 상관없이 원하는 컬럼의 값 분포정보입니다. 이 통계정보는 information_schema.statistics 테이블에 저장됩니다. 이를 통해 어떤 인덱스를 사용해서 데이터를 조회할 지를 결정합니다. 통계정보가 잘못된 경우는 옵티마이저가 최고의 실행계획을 찾지 못할 수 있습니다. [MySQL/MariaDB 통계정보] 구분 내용 수집량 소량 페이지 샘플링 분석 후 예측(InnoDB), 인덱스 전체페이지(MyISAM) Cardinality = Total Rows / Num_Distinct information_schema.statistics userstat = ON (Enable) 정확도 예측기반(InnoDB), 거의 실측치(MyISAM) 통계수집 Eve nt 동적 Event(InnoDB) - 테이블 첫 오픈시점 - SHOW TABLE STATUS LIKE ‘~’;시 - SHOW INDEX FROM ~; - DDL 수행 - innodb_stats_on_metadata=1 경우 information_schema Data 조회 시 - Table Data 6.25%(5.5), 10%(5.6) 변경 시 명시적 (MyISAM) - ANALYZE TABLE ~; 영구적 통계정보 - 5.5 이하 불가능 - 5.6 이상에서부터 지원 mysql.innodb_table_stats mysql.innodb_index_stats innodb_stats_persistent=0/1 #위 테이블에 영구저장 여부 innodb_stats_auto_recalc=0/1 #자동수집 여부 히스토그램 - MariaDB 10.0 부터 지원, mysql 미지원 - Mysql.table_stats, mysql.column_stats, mysql.index_stats user_stat_tables=NEVER histogram_size=255 (0~255) histogram_type=SINGLE_PREC_HB / DOUBLE_PREC_HB 옵티마이저의 optimizer_use_condition_selectivity=1~5 1(기본), 2(인덱스선택도), 3(모든컬럼선택도), 4(히스토그램), 5(4+레코드 샘플링)
  17. 17 3.3. 옵티마이저(Optimizer) MySQL./MariaDB 의 옵티마이저는 비용기반옵티마이저(CBO)로 각 테이블의 데이터가 어떤 분포로 저장돼 있는지 통계정보를 참조하여 최적의 실행계획을 수립하는 작업을 담당한다. 1. 사용자의 요청 쿼리 문장을 최소비용으로 가장 빠르게 처리할 지 결정 2. 쿼리를 변환 3. 비용을 최적화 4. 실행계획을 개선 합니다. 옵티마이저는 비용예측 시 캐시의 영향은 고려하지 않습니다. 다만 모든 데이터에 대한 접근(Read)은 실제 Disk IO 가 필요하다고 가정하고 비용을 산정합니다. 또한 스토어드 루틴(프로시저, 함수)등 자신의 통제하에 있지 않는 명령에 대해서는 비용을 고려하지 않습니다. 또한 옵티마이저는 가능한 모든 실행가능한 계획의 비용을 예측하는 것이 아니므로, 선택한 실행계획이 최적의 실행계획이 아닐 수도 있습니다. 다음은 옵티마이저가 최적화를 알고 있는 일부 몇가지 경우입니다. 1. 조인순서를 조정 2. OUTER JOIN 을 INNER JOIN 으로 변경 3. 불가능/불필요 조건제거 4. COUNT(), MIN(), MAX()최적화 5. 쿼리간소화 및 상수화 6. 커버링 인덱스 선택 7. 서브쿼리 최적화 8. 조기종료처리
  18. 18 3.4. 실행계획(Explain) MySQL 에서는 쿼리의 실행계획을 확인하는 방법으로 Explain 명령어를 이용합니다. 수행하고자 하는 SQL 문장앞에 Explain 을 추가 함으로서 SQL 에 대한 실행계획을 확인합니다. 다음의 예를 보자. mysql> EXPLAIN SELECT HOST, USER, PASSWORD FROM mysql.user; id select_type table type possible_keys key key_len ref rows Extra ------ ----------- ------ ------ ------------- ------ ------- ------ ------ -------- 1 SIMPLE user ALL (NULL) (NULL) (NULL) (NULL) 7 (NULL) Explain 을 통해 SQL 에 대한 실행계획 결과를 보면 id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra 등의 정보를 볼 수 있다. Explain 은 select 문에 사용된 각 테이블당 하나의 행을 리턴한다. 또한 나열된 순서는 MySQL 이 쿼리의 처리를 위해 수행한 순서를 가지고 출력된다. 타 DBMS 의 실행계획을 보면 단일테이블의 데이터를 찾는 순서가 Index 를 거쳐서 데이터 블록을 찾는 순서에 대해서 좀더 세부적으로 Plan 을 볼 수 있는 것에 비해 조금 아쉬운 부분이 있다. 참고로 MySQL 에서 EXPLAIN = DESCRIBE = DESC 는 동의어(synonyms) 입니다. {EXPLAIN | DESCRIBE | DESC } tbl_name [col_name | wild]; {EXPLAIN | DESCRIBE | DESC } {EXTENDED | PARTITIONS} SELECT select_options; Explain 을 통해서 우리는 - 옵티마이저가 어떻게 쿼리를 변환했는지 - 우리가 원하는 조인 순서가 맞는지 - 해당 테이블의 인덱스를 적절히 사용하고 있는지 - 사용하는 인덱스를 통해서 힌트를 추가하거나 SQL 을 수정해야 하는 것은 아닌지 를 확인해야 합니다. 결과셋은 하나의 테이블을 읽을 때의 정보를 보여주며 각 컬럼의 구성은 다음과 같다. 컬럼 설명 id 한 테이블의 SELECT 번호, 쿼리내의 SELECT 의 구분번호. select_type SELECT 의 타입(SIMPLE, PRIMARY, UNION, SUBQUERY, DRIVED…) table 해당 table 명 type 조인의 타입(system, const, eq_ref, ref, ref_or_null, index_merge…) passible_keys 테이블의 사용가능한 인덱스들 명. key Passible_keys 값들 중에서 실제 사용한 인덱스(key) Key_len Where 절에 사용한 인덱스의 길이(byte) ref 행을 추출하는데 key 와 함께 사용한 컬럼이나 상수 rows 쿼리수행을 위해 검사대상 예상행수 filtered 조건절에 의해 필터링되는 행의 비율 Extra 쿼리를 해석한 추가적인 정보
  19. 19 3.5. 프로파일링(Profiling) 프로파일은 MySQL 의 현 세션에서 수행했던 최근 SQL 에 대한 Resource 사용정보를 보여준다. SQL 수행하는데 어느 부분에서 자원을 많이 사용하며 어디에 병목이 발생하고 있는지 확인할 수 있다. 이는 실행계획과 더불어 자원의 효율적인 사용을 위해서 참고할 만한 자료로 사용할 수 있다. SELECT ~; SHOW PROFILES; SHOW PROFILE [ALL | BLOCK TO | CONTEXT SWITCHES | CPU | IPC|MEMORY|PAGE FAULTS|SOURCE|SWAPS] [FOR QUERY n] [LIMIT row_count [OFFSET offset]] mysql> show profiles; +----------+------------+-----------------------+ | Query_ID | Duration | Query | +----------+------------+-----------------------+ | 1 | 0.00027225 | select * from test.t1 | mysql> show profile; +----------------+----------+ | Status | Duration | +----------------+----------+ | starting | 0.000074 | | query end | 0.000010 | | closing tables | 0.000005 | | freeing items | 0.000018 | | cleaning up | 0.000017 | +----------------+----------+ Mysql> show profile ALL; # 결과는? SHOW PROFILES/PROFILE 은 5.6.7 에서 deprecated 되었습니다. 향후에는 performance_schema 를 활용하시기 바랍니다. # performance_schema 를 시작/설정하는 방법 https://dev.mysql.com/doc/refman/5.6/en/performance-schema-startup-configuration.html # performance_schema 로 프로파일링 하는 방법 https://dev.mysql.com/doc/refman/5.6/en/performance-schema-query-profiling.html
  20. 20 4. Explain 파해치기 MySQL 5.6.3 까지는 UPDATE, INSERT, DELETE, REPLACE 등에 대한 실행계획은 지원하지 않아서 SELECT 절로 변환해서 확인했다. 그러나 5.6.3 부터는 모두 지원한다. Explain 수행결과에 컬럼들의 정보는 다음과 같다. 4.1. id 한 테이블의 SELECT 번호, 쿼리내의 SELECT 의 구분번호를 의미하며, 쿼리의 처리하는 테이블의 순서로 이해하면 된다. 여러 개의 테이블 조인 시에 테이블의 개수만큼 실행계획 레코드가 생기지만 ID 는 동일하게 부여. 4.2. select_type 어떤유형의 select 타입인지를 의미한다. 다음의 표를 참고하세요. Select_type 설명 SIMPLE UNION 이나 SUBQUERY 를 사용하지 않는 단순 SELECT PRIMARY 쿼리 제일 바깥쪽에 있는 SELECT DERIVED SELECT 절로 추출된 테이블로 FROM 절 내부의 SUBQUERY 의미 UNION UNION 절에서 두번째 이후 SELECT 단위, 첫번째는 DRIVED DEPENDENT UNION 내부쿼리가 외부값을 참조하는 UNION 절 테이블 UNION RESULT UNION 결과값에 대한 임시 테이블 SUBQUERY FROM 절 이외의 서브쿼리의미. DEPENDENT SUBQUERY 서브쿼리가 바깥쪽 SELECT 절의 정의 컬럼값을 참조 UNCHACHEABLE SUBQUERY 서브쿼리결과가 외부쿼리의 변하는 값에 따라 매번 새로생성형태. UNCHACHEABLE UNION 캐싱이 불가능한 요소를 포함한 UNION 개별 type 에 대한 예제는 다음과 같다. mysql> EXPLAIN select * from t1 where id=1; id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 N const PRIMARY PRIMARY 4 const 1 100 N mysql>EXPLAIN SELECT t2.nm ,(SELECT COUNT(*) FROM t2 WHERE nm=nm) AS cnt FROM t1 INNER JOIN t2 ON t2.nm=t1.nm WHERE t2.del_yn='Y'
  21. 21 id select_type tabl e pa rtit io ns ty pe possible_ keys key key_len ref rows filtered Extra 1 PRIMARY t2 N AL L PRIMAR Y N N N 3 33.33 Using where 1 PRIMARY t1 N AL L N N N N 2 50 Using where; Using join buffer (Block Nested Loop) 2 SUBQUER Y N N N N N N N N N Select tables optimized away mysql> EXPLAIN SELECT t1.nm ,COUNT(*) AS cnt FROM ( SELECT 'a' AS nm ,t2.del_yn FROM t2 GROUP BY del_yn ) a INNER JOIN t1 ON t1.nm = a.nm WHERE a.nm='a' GROUP BY t1.nm; id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 N ALL N N N N 2 50 Using where 1 PRIMARY <derived2 > N ref <auto_key0> <auto_key0 > 5 const 1 100 N 2 DERIVED t2 N ALL N N N N 3 100 Using temporary; Using filesort
  22. 22 mysql>EXPLAIN SELECT t1.nm FROM t1 GROUP BY nm UNION SELECT t2.nm FROM t2 id select_type table partition s type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 N ALL N N N N 2 100 Using temporary; Using filesort 2 UNION t2 N index N PRIMARY 302 N 3 100 Using index N UNION RESULT <union1,2> N ALL N N N N N N Using temporary mysql> EXPLAIN SELECT COUNT(*) FROM ( SELECT '1' AS C1, t1.nm FROM t1 GROUP BY nm UNION SELECT '2', t2.nm FROM t2 UNION SELECT '3', t2.nm FROM t2 WHERE del_yn='Y' ) B 1 PRIMARY <derived2> N ALL N N N N 7 100 N 2 DERIVED t1 N ALL N N N N 2 100 Using temporary; Using filesort 3 UNION t2 N index N PRIMARY 302 N 3 100 Using index 4 UNION t2 N ALL N N N N 3 33.33 Using where N UNION RESULT <union2,3,4> N ALL N N N N N N Using temporary mysql> EXPLAIN SELECT nm FROM t1 WHERE EXISTS (SELECT 1 UNION ALL SELECT 1 FROM t2 WHERE t2.nm = t1.nm ) id select_type table partition s type possible_keys key key_le n ref rows filtere d Extra 1 PRIMARY t1 N ALL N N N N 2 100 Using where 2 UNCACHEABL E SUBQUERY N N N N N N N N N No tables used 3 DEPENDENT UNION t2 N eq_ref PRIMARY PRIMARY 302 test.t1.nm 1 100 Using index mysql> EXPLAIN SELECT *
  23. 23 FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.nm = t1.nm); id select_type table partition s type possible_key s key key_len ref rows filtere d Extra 1 PRIMARY t1 N ALL N N N N 2 100 Using where 2 DEPENDENT SUBQUERY t2 N eq_ref PRIMARY PRIMARY 302 test.t1.nm 1 100 Using index mysql> EXPLAIN SELECT * FROM t1 WHERE id = (SELECT @status FROM t2 WHERE t2.nm='a'); id select_type tabl e partitions type possible_key s key key_len ref rows filtere d Extra 1 PRIMARY t1 N ALL N N N N 2 100 Using where 2 UNCACHEABLE SUBQUERY t2 N const PRIMARY PRIMARY 302 const 1 100 Using index mysql> EXPLAIN SELECT * FROM t1 WHERE id IN (SELECT @status FROM t2 WHERE t2.nm='a' UNION ALL SELECT 1); id select_type table partition s type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 N ALL N N N N 2 100 Using where 2 DEPENDENT SUBQUERY t2 N const PRIMARY PRIMARY 302 const 1 100 Using index 3 DEPENDENT UNION N N N N N N N N N No tables used
  24. 24 4.3. table SELECT 절에 대한 데이터를 읽어들이는 테이블명을 말한다. 해당 테이블명 또는 테이블에 대한 Alias, 서브쿼리등으로 인한 가상의 테이블(<derived#n>을 의미한다. 단순한 쿼리의 경우는 쉽게 확인이 가능하나, 복잡한 쿼리의 경우는 이해가 다소 어렵다. 4.4. type 조인타입 또는 테이블 접근방식(Access type)으로 이해하면 쉽다. 풀스캔을 하는지, 인덱스를 사용하는지, unique 키를 사용하는지 등을 판단하여 성능판단의 주요지표이며 아래의 type 순서는 옵티마이저의 효율적인 순서(높음>중간>낮음)대로 정리합니다. type 설명 system table 에 하나의 row 만 가지는 const 의 특별한 형태 const PK 나 Unique 키에 반드시 1 건에 대한 등가(=)조건에 대한 접근 eq_ref 조인시 첫째컬럼값으로 두번째 테이블등의 PK, Unique 등에 등가(=) 1 건 접근. ref 조인시 인덱스에 대해 등가(=)접근하나 1 건이라는 보장이 없는 접근 fulltext 전문 검색 인덱스 사용하는 접근시(Where MATCH(?) AGAINST (~) 사용) ref_or_null NULL 비교가 추가된 ref 접근 형태 index_merge 해당 테이블의 두개이상의 인덱스를 사용한 검색결과에 대한 병합한 형태 unique_subquery IN 절에서 서브쿼리가 중복없는 unique 값을 반환하는 형태 index_subquery IN 절에서 서브쿼리가 중복이 있으나 INDEX 를 이용해 제거할 수 있는 형태 range 대소 비교연산자를 이용해서 인덱스 걸린 컬럼 검색시. index 인덱스 풀스캔. 인덱스를 처음부터 끝까지 조건없이 읽는 형태. ALL 풀 테이블 스캔. - Index Range Scan 은 type 이 const, eq_ref, ref 인경우를 의미하며 성능상 좋은 접근방법입니다. [system] mysql> EXPLAIN SELECT * FROM mysql.db; id select_type tabl e partition s type possible_key s key key_le n ref row s filtered Extra "1 " "SIMPLE" db N system "" "" "" "1" "100.00 " - 하나의 row 만 가지는 테이블 Access 시 나타나는것으로 const 의 특별한 유형.(system table) [const] mysql> EXPLAIN SELECT * FROM t1
  25. 25 WHERE id = 1; id select_type table partition s type possible_key s key key_len ref rows filtered Extra 1 SIMPLE t1 N const N N N N 1 100 [eq_ref] mysql> EXPLAIN SELECT t1.* FROM t3 INNER JOIN t1 ON t1.id=t3.id; i d select_type tabl e partitions type possible_key s key key_len ref rows filtered Extra 1 SIMPLE t3 N index PRIMARY PRIMARY 4 N 2 100 Using index 2 SIMPLE T1 N eq_re f PRIMARY PRIMARY 4 test.t3.i d 1 100 [ref] mysql> EXPLAIN SELECT t2.nm FROM t1 INNER JOIN t2 ON t2.nm=t1.nm WHERE t1.nm ='a'; i d select_type tabl e partitions type possible_key s key key_len ref rows filtered Extra 1 SIMPLE T2 N const PRIMARY PRIMARY 4 N 2 100 Using index 2 SIMPLE T1 N ref nm nm 4 test.t3.i d 1 100 [ref_or_null] mysql> EXPLAIN SELECT id, nm FROM t1 WHERE nm = 'a' OR nm IS NULL; id select_type table partitions type possible_key s key key_le n ref rows filtered Extra "1 " "SIMPLE" "t1" N "ref_or_null " "nm" "nm" "303" "const" "2" "100.00" "Using where; Using index" [index_merge] mysql> EXPLAIN SELECT * FROM tbl_name WHERE key1 = 10 OR key2 = 20; id select_typ e table partition s type possible_key s key key_le n ref row s filtered Extra "1 "SIMPLE" "tbl_name N Index_merge Key1, key2 Key1, key2 4,4 null "1" "100.00 Using
  26. 26 " " " union(~ ) [unique_subquery] mysql> EXPLAIN ~ VALUE IN (SELECT primary_key FROM single_table WHERE some_expr); [index_subquery] mysql> EXPLAIN ~ VALUE IN (SELECT key_column FROM single_table WHERE some_expr); [range] mysql> EXPLAIN SELECT nm FROM t1 WHERE nm>'a'; id select_typ e table partition s type possible_keys key key_le n ref rows filtere d Extra "1 " "SIMPLE" "t1" null " range " "nm" nm 303 cons t 1 100" Using where ; Using index [index] mysql> EXPLAIN SELECT nm FROM t1 WHERE nm>='a'; id select_typ e table partition s type possible_keys key key_le n ref rows filtere d Extra "1 " "SIMPLE" "t1" null index "nm" nm 303 cons t 1 100" Using where ; Using index [ALL] mysql> EXPLAIN SELECT * FROM t1; id select_typ e table partition s type possible_keys key key_le n ref rows filtere d Extr a "1 " "SIMPLE" "t1" ALL "" 2 100"
  27. 27 4.5. possible_keys 해당 테이블을 검색할 때 사용할 수 있는 인덱스들의 정보입니다. 이 값이 NULL 이면 사용가능 인덱스가 없다는 의미입니다. 이 값의 순서는 의미가 없으며, 사용되지 않을수도 있습니다. 이 값이 NULL 인경우는 Where 절을 검사하여 적절한 인덱스를 생성해서 쿼리의 성능향상을 도모할 필요가 있습니다. 4.6. key possible_keys 의 인덱스들 중에서 실제 사용한 인덱스 정보를 의미합니다. 이 값을 통해서 개발자/DBA 는 사용된 index 정보를 확인할 수 있습니다. 실행계획 풀테이블 스캔인 type=ALL 이면 key=NULL 로 표시되며, index_merge 인 경우는 하나이상의 인덱스를 가질 수 있다. 만약 옵티마이저가 선택한 인덱스에 대하여 무시하거나 다른 인덱스를 사용하도록 할 경우는 FORCE INDEX / USE INDEX/ IGNORE INDEX 힌트를 통해서 해당 쿼리의 실행계획을 변경할 수 있습니다. SELECT nm FROM t1 USE INDEX(PRIMARY); SELECT nm FROM t1 FORCE INDEX(nm); SELECT nm FROM t1 IGNORE INDEX(nm); 4.7. key_len 해당 테이블의 사용한 인덱스의 길이를 의미하며, key=NULL 이면 key_len=NULL 이다. 또한 실제 복수컬럼 키중 얼마나 많은 부분을 사용할 것인지 알 수 있다. 단순히 키 길이가 의미가 없다고 판단할 수 있으나, key_len 이 중요한 이유는 Where 에 대한 제약조건을 통해서 해당 인덱스에서 key 로 사용된 컬럼들의 길이의 총 합이다. 이 의미는 인덱스에 있는 컬럼 이더라도 Key조건으로 사용되는 경우는 key_len 에 포함되지만, Covered Index 의 활용되는 사례처럼 Filter 조건으로 사용되는 경우는 해당컬럼의 길이는 포함되지 않는다. 이 값은 길이가 아니라 BYTE 를 의미합니다. # charset = UTF8 인경우 CREATE TABLE t4 (id INT NOT NULL , nm VARCHAR(100), cmt VARCHAR(20), rdate DATETIME, del_yn VARCHAR(1), PRIMARY KEY(id), KEY(nm,del_yn)); SELECT * FROM t4 WHERE nm ='a'; SELECT * FROM t4 WHERE nm ='a' AND del_yn=’Y’; SELECT * FROM t4 WHERE nm ='a' AND del_yn like ’%Y%’; # key_len 의 값은?
  28. 28 4.8. ref ref 는 사용된 인덱스의 key 로서 사용된 컬럼이나 상수값을 나타냅니다. 만약 ref=func 이면 이는 특정 함수를 통해서 얻어진 결과값을 의미합니다. 4.9. rows 이는 쿼리를 수행하기 위해 해당테이블을 조사해야 하는 행수입니다. InnoDB 의 경우 이값은 추정치를 나타내며, 항상 정확하지는 않습니다. 4.10. filtered 테이블의 제약조건에 의해서 필터링됩니다. 이값은 해당 테이블의 행의 예상비율을 나타냅니다. 4.9 의 rows 값(추청되는 조사할 행수)에 filtered 비율을 곱하면 이 값이 이전 테이블과 조인될 때 사용될 것으로 예상되는 rows 값을 찾을 수 있다. 4.11. Extra 이 값은 옵티마이저가 쿼리를 어떻게 해석해서 어떤 방식으로 Access 하는지에 대한 추가정보를 제공합니다. Extra 가 가지는 값들은 다음과 같다. 항목 설명 const row not found type=const 로 Access 했으나 대상테이블이 empty 테이블인 경우 Distinct 테이블 결과값이 중복없이 Unique 한 결과인 경우 Full Scan on Null key in 절 쿼리중 Outer query 에서 NULL 값이 공급되는 경우 발생함. Index lookup 실패로 Full Table Scan 이 발생할 수 있음 Impossible Having Having 절 항상 False. Select 연산 안함. Impossible Where Where 절 항상 False. Select 연산 안함. Impossible WHERE noticed after reading const tables const/system 유형의 테이블 읽은 후 Where 절이 항상 False. No tables used from 절 테이블 명시안됨. from dual 구문 Not existed Left join 절을 Not Exists 형태로 옵티마이저가 최적화 하는 경우 range checked for each record (index map: N) 조인에 적절한 인덱스가 없어서, 선행테이블 컬럼값에 따라 각각 row 에 대해서 range / index merge 를 검토함을 의미 N 값은 어떤 인덱스를 검토되는지 표시 Select tables optimized away Select 절에 집계함수만 있는 경우, 옵티마이저는 Index Lookup 후 1 개의 결과만 리턴하고 끝. unique row not found select ~ from table 쿼리에서 Key/PK Index 에 만족하는 row 가 없는경우 Using filesort 정렬결과를 만들기 위해 물리적인 정렬작업을 수행
  29. 29 Using index Index 내에서 모든 결과값을 리턴하는 경우(Covering Index) 인덱스 통해서 lookup 과정이 수행되면 NULL 값임. Using index for group-by Index 내에서 group by / distinct 처리 Using join buffer join 처리를 위한 Index 가 없을경우 join 시 memory 의 join_buffer 사용함을 의미. Using sort_union(...), Using union(...), Using intersect(...) Index Merge 수행. 두개이상의 인덱스를 동시에 사용하여 처리. Using temporary 쿼리처리를 위하여 임시테이블을 생성함. group by, order by 등에 인덱스 사용 못할 때 발생. Using where where 절이 다음조인에 사용될 행이나, Client 에 전송할 result 제한하는 경우. type 이 ALL 이나 Index 값이면서 Extra 가 Using where 가 아니면 쿼리상에 문제가 있는 경우로 확인필요. Using where with pushed condition InnoDB 에서는 발생안함(Only NDB) Using MRR 테이블을 읽을 때 다중범위 읽기 최적화 전략 수행시 해당. Secondary Index 의 랜덤 IO 를 순차 IO 로 변경해서 eq join 수행. http://dev.mysql.com/doc/refman/5.7/en/mrr-optimization.html Using index condition mysql 5.6 이상 Filtering 조건처리를 mysql 엔진이 아닌 InnoDB 엔진에 pushdown. 불필요 IO 줄여 빠른응답성능 제공. Start temporary, End temporary mysql 5.6 에서 semi-join 최적화. 조인후에 중복제거하는 전략이용하여 semi-join(exist or in 절 select) 수행. Skip_open_table, Open_frm_only, Open_trigger_only Open_full_table information_schema 조회시 발생. - Extra 값에 Using filesort 나 Using temporary 면 실행계획을 보다 면밀히 확인할 필요가 있습니다. 의도된 계획이거나 인덱스 값 확인 등을 통해서 실행계획을 재검토 한다.
  30. 30 5. SQL 을 위한 인덱싱 전략 5.1 SQL 상의 컬럼가공 제거 SELECT nm FROM t1 Where id/2=1; SELECT nm FROM t1 where substring(nm, 1,3)=’abc’; SELECT nm FROM t1 where to_days(current_date)-to_days(dt)<=10; 제약조건이나 조인조건상에 있는 컬럼의 경우에 컬럼을 가공/병합 처리등으로 원본컬럼값을 가공한다면 인덱스를 정상적으로 사용할 수 없다. 흔히 하는 실수가 컬럼값에서 문자열을 잘라와서 비교하거나, 날짜구간 계산의 비효율적인 사용이 대표적인 경우다. 5.2 클러스터링 인덱스(테이블) InnoDB 클러스터 인덱스는 전혀다른 의미의 인덱스가 아니다. 실제로 이는 B-Tree 구조의 인덱스정보와 Data 행값을 함께 가지고 저장한다. Root -Branch – Leaf 구조에서 Data 는 Leaf 에 저장된다. 테이블은 오로지 하나의 클러스터 인덱스만 가질 수 있으며, 만약 클러스터 인덱스를 생성하지 않으면 가상의 6byte ROW_ID 를 생성한다. 이렇게 기본 키(Primary Key)에 따라서 데이터를 묵는다. 클러스터 인덱스 구성 시 몇가지 주의사항 - 데이터 Insert 시에는 기본키 순서에 따라서 삽입하는 것이 유리. - 클러스터 인덱스의 컬럼크기는 작을수록 좋다. - 자주 변경되는 컬럼은 기본키로 적합하지 않다. - 기본키만이 클러스터 인덱스로 생성된다. 이는 조금 혼돈스럽다. MySQL 은 키의 개념과 클러스터링 개념을 혼합해서 관리한다. - 클러스터 인덱스 구조상 페이지의 분할을 고려해야 한다. 5.3 커버링 인덱스 불필요하게 여러컬럼을 읽지 않아도 되는 경우는 커버링 인덱스를 통해서 성능을 향상시킬 수 있다. 쿼리결과에 필요한 데이터가 모두 포함된 인덱스를 커버링 인덱스라고 한다. 쿼리가 커버링 인덱스를 적용하면 Explain 의 Extra 컬럼에 “Using Index”로 표시된다. 커버링 인덱스의 장점은 다음과 같다. - 보조인덱스( NonClustered Index)만으로 데이터 결과셋을 완성할 수 있어 속도가 빠르다. - 데이터가 정렬되어 있어서 무작위로 클러스터링 인덱스의 무작위 위치에서 가져오는것에 비해 IO 가 적게 든다. - 최선은 Where + Select 결과절까지의 컬럼을 커버하는 경우이며, Where 조건절의 컬럼은 커버링 인덱스에 포함하는 것이 좋다.
  31. 31 5.4 압축(프리픽스) 인덱스 인덱스를 생성하고자 하는 경우 특정컬럼의 크기가 큰경우, 인덱스 컬럼의 특정길이 만큼만 인덱스 구성이 가능하다. 지원가능한 컬럼타입은 char, varchar, binary, varbinary, text CREATE TABLE TBL(ID INT, NAME VARCHAR(1000)); CREATE INDEX TBL_IDX ON TBL ( NAME(10) ); INNODB 의 innodb_large_prefix 옵션이 꺼져있는 경우는 767byte, 켜져있는경우는 3072 byte 까지 컬럼크기 만큼 생성할 수 있다. 5.5 인덱스 개수를 최소로 구성(중복제거) 인덱스의 수가 증가하면 DML 에 따른 데이터 변경적재에 심각한 성능저하가 발생할 수 있다. 인덱스의 수와 DML 속도는 Trade-Off 관계로서 운영시스템의 SQL 조건들에 따라 적절한 인덱스의 개수를 유지하는 것이 좋다. 또한 중복된 인덱스를 구성하지 않도록 관리해야 한다. CREATE TABLE TBL(ID INT PRIMARY KEY, NM1 VARCHAR(10), NM2 VARCHAR(10)); CREATE INDEX TBL_IDX1 ON TBL ( NM1 ); CREATE INDEX TBL_IDX2 ON TBL ( NM1, ID); #? 5.6 다중컬럼 인덱스 흔히들 단일컬럼 인덱스 만드는 것과 다중컬럼 인덱스를 만든는 것의 차이를 이야기 하곤 한다. 단일 컬럼 인덱스보다 다중컬럼 인덱스를 사용할 것을 권장한다. 5.7 복합정렬의 주의 여러컬럼에 대해서 group by 나 정렬이 필요한 경우, MySQL 에서는 ASC 만 사용하는 것이 좋다. 현재 MySQL 5.7 까지 ASC 와 DESC 를 혼합한 경우 DESC 는 지원하지 않아서 filesort 를 피할 수 없다. 이런 경우는 데이터를 ASC 화 해서 저장하거나 가상컬럼을 이용해서 DESC 방식을 우회할 수 있다. 5.8 정리 - 제일 많이 수행되는 쿼리를 확인. - 모든 쿼리를 만족시키는 인덱스 전략은 없다. 인덱스의 구성과 속도의 타협이 필요하다. - 등가비교컬럼이 선두컬럼이 되도록 인덱싱한다. - 컬럼 크기는 되도록 작게 prefix 인덱스를 적절히 활용한다. - 모든 데이터 결과처리를 MySQL 의 인덱스등으로만 수행하려는 생각은 재고해야 한다. - 비정규화, 집계테이블, 캐싱등을 적절히 활용한다.
  32. 32 6. SQL 작성 가이드 아래내용은 절대적인 기준은 아니며, 팀/조직 내부의 표준화 정책에 따라 달라질 수 있습니다. - SQL TEXT 에 대하여 표준화 하라. 예를 들면 table, column 등은 소문자로, 나머지는 대문자로 통일 등. 세부항목들의 정리. - 당연히 ANSI-SQL 규약에 충실하자. - Application_ID 형태의 주석삽입은 운영 편의성을 제공한다. SELECT /* com.app.mem.select */ * FROM tbl~; - TAB 과 개행에 규칙을 부여하라. (EX: TAB=4 SPACE, ‘,’는 컬럼뒤, FROM/JOIN/WHERE 등은 개행) SELECT COL1, COL2 FROM TBL_A WHERE ID=123; - 연산자 다음은 한칸 띄운다. - WHERE 이나 JOIN 에 사용되는 컬럼의 데이터 타입은 같게 한다. - JOIN 시에도 DRIVING 테이블의 컬럼은 우변으로 DRIVEN 테이블은 좌변으로 위치한다. - 서브쿼리보다는 JOIN 을 사용한다. SELECT ID FROM TBL_A INNER JOIN TBL_B ON TBL_B.COL1 = TBL_A.COL1 (O) ON TBL_A.COL1 = TBL_B.COL1 (X) WHERE ~; - 되도록이면 등가비교(=)로 처리한다. - 부정형 보다는 긍정형으로 SQL 작성한다. (NOT IN(X)) - 되도록이면 수행되는 선행테이블 순서대로 조인한다. 가독하기 쉽다. - ALIAS RULE 을 적용하라.(A~Z 할지, 업무규약 약칭을 사용할지) - SELECT * 구문은 사용하지 않는다.
  33. 33 - 특별한 경우가 아니면 STORED ROUTINE 은 지양한다. - A4 여러장 짜리의 복잡한 JOIN 을 활용한 단일쿼리는 되도록 지양한다. 가독성도 떨어지고, 운영상의 문제을 만드는 경우가 많다. - SQL 작성 후 반드시 EXPLAIN 을 통해서 원하는 실행계획대로 수행하는지 확인한다. - 가급적이면 불필요한 시스템 함수사용은 자제한다. APPLICATION 영역에서 할일이지 DBMS 에서 처리할 일은 아닌것들이 더 많다. - 전체집합처리보다 부분집합처리로 결과절을 만들려고 노력하자.
Publicidad