-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Chapter11. 쿼리 작성 및 최적화
1. 쿼리 작성과 연관된 시스템 변수
MySQL 서버의 시스템 설정에 따라 SQL 작성 규칙이 달라질 수 있다.
1-1. SQL 모드
테이블 및 인덱스 통계 정보
sql_mode 시스템 설정에 여러 개의 값이 동시에 설정
STRICT_ALL_TABLES & STRICT_TRANS_TABLES: insert, update 시 칼럼 타입과 저장되는 값의 타입이 다를 때 타입 변경ANSI_QUOTES: 문자열 값에 홑따옴표만 사용ONLY_FULL_GROUP_BY: GROUP BY 절이 사용된 문장의 SELECT 절에는 GROUP BY 절에 명시된 칼럼과 집계 함수만 사용PIPE_AS_CONCAT:||을 문자열 연결 연산자로 사용PAD_CHAR_TO_FULL_LENGTH: CHAR 타입에서 유효 문자열 뒤의 공백 문자 제거NO_BACKSLASH_ESCAPES: 역슬래시 문자를 이스케이프 문자로 사용IGNORE_SPACE: 스토어드 프로시저나 함수명과 괄호 사이의 공백을 무시REAL_AS_FLOAT: REAL 타입이 기본적으로 DOUBLE의 동의어로 사용되는데 FLOAT로 바꿀지NO_ZERO_IN_DATE & NO_ZERO_DATE: DATE, DATETIME 타입 칼럼에 잘못된 날짜 저장ANSI: MySQL 서버가 최대한 SQL 표준에 맞게 동작하도록TRADITIONAL: 더 엄격하게 SQL 작동 제어 (STRICT_ALL_TABLES & STRICT_TRANS_TABLES)
영문 대소문자 구분
MYSQL 서버는 설치된 운영체제에 따라 테이블명의 대소문자를 구분한다 (윈도우는 구분 X, 유닉스는 구분)
운영체제와 관계없이 대소문자 구분 영향을 받지 않게 하려면 lower_case_table_names 시스템 변수 설정
MYSQL 예약어
데이터베이스나 테이블 칼럼의 이름을 예약어와 같은 키워드로 생성하면 해당 칼럼이나 테이블을 SQL에서 사용할 때 역따옴표나 쌍따옴표로 감싸야한다
예약어를 모두 기억하기 어려우므로 직접 MYSQL 테이블을 생성해서 예약어인지 알아볼 수 있다(에러로 알려줌)
1-2. 매뉴얼의 SQL 문법 표기를 읽는 방법
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[(col_name [, col_name] ...)]
{ {VALUES | VALUE} (value_list) [, (value_list)] ... }
[AS row_alias[(col_alias [, col_alias] ...)]]
[ON DUPLICATE KEY UPDATE assignment_list]- 키워드: 대문자로 표기 (대소문자 구분 X)
- 토큰: 이탤릭체. 테이블명/칼럼명/표현식
[]해당 키워드나 표현식이 선택사항일 때|앞과 뒤의 키워드나 표현식 중에서 하나만 선택해서 사용{}괄호 내 아이템 중 반드시 하나를 사용...은 앞에 명시된 키워드나 표현식 조합이 반복될 수 있음을 의미
1-3. MySQL 연산자와 내장 함수
리터럴 표기법 문자열
문자열
- 홑따옴표와 쌍따옴표를 사용해 문자열 표기
- 문자열에 홑따옴표가 포함되어 있을 때는 홑따옴표 두 번 연속해서 입력하거나 쌍따옴표와 홑따옴표 혼합
- 식별자가 키워드와 충돌할 때는 역따옴표로 감싸서 사용
숫자
- 따옴표 없이 숫자 값을 입력
- 문자열 형태로 따옴표를 사용하더라도 비교 대상이 숫자 값이거나 숫자 타입의 칼럼이면 자동 변환. 숫자 타입을 문자열 타입보다 우선시하므로 문자열 값을 숫자 값으로 변환
SELECT * from test WHERE number_column = '10001';
SELECT * from test WHERE string_column = 10001;- 첫번째에서는 상수값만 숫자로 변환하지만 두번째에서는 string_column의 모든 문자열을 숫자로 변환해서 비교하므로 인덱스가 있더라도 이용하지 못한다
=> 숫자 값은 숫자 타입의 칼럼에만 저장하자
날짜
- 정해진 형태의 날짜 포맷을 자동으로 DATE나 DATETIME 값으로 변환
불리언
- BOOL이나 BOOLEAN은 TINYINT 타입의 동의어
- TRUE, FALSE 로 비교하지만 실제 값은 0,1 (TRUE는 1만을 의미한다)
- 모든 숫자값이 아닌 0,1만 매필되기 때문에 불리언 타입은 ENUM 타입으로 관리하는 것이 좋다
MySQL 연산자
동등 비교
- = 과 <=>
- <=> 은 Null 값도 하나의 값으로 생각하고 비교. (원래는 null 값에 대한 비교 결과는 null)
부정 비교
- <> 과 !=
Not 연산자
- NOT 과 !
AND, OR 연산자
- AND 과 &&
- OR 와 ||
- ||은 문자열 결합에도 사용될 수 있다
- AND와 OR 연산자가 동시에 사용되면 AND 연산자가 우선순위 가짐
DIV, MOD 연산자
- DIV 과 /
- MOD 와 %
REGEXP 연산자
- 문자열 값이 패턴을 만족하는지 확인하는 연산자 (RLIKE)
- REGEXP 연산자를 문자열 칼럼 비교에 사용할 때 인덱스 레인지 스캔을 사용할 수 없다. 가능하면 데이터 조회 범위를 줄일 수 있는 조건과 함께 사용해야 성능상 좋다
LIKE 연산자
- %와 _ 와일드 카드를 사용해 문자열을 비교할 수 있다 (처음부터 끝까지 일치해야한다)
- 인덱스를 이용해 처리할 수 있다 (와일드 카드 문자가 검색어의 뒤 쪽에 있을 때만 인덱스 레인지 스캔. 아니라면 인덱스 풀 스캔)
BETWEEN 연산자
- BETWEEN 범위의 모든 인덱스를 검색해야한다
- 비슷한 연산자인 IN이 있는데 처리 방법이 다르다. IN의 처리 방법은 동등 연산자와 비슷하다. BETWEEN은 선형으로 인덱스를 검색하는데, IN은 동등 비교를 여러번 수행하는 방식으로 검색한다.
IN 연산자
- 여러 개의 값에 대해 동등 비교 연산을 수행
- 상수를 사용하거나 서브쿼리를 사용할 수 있음
- NOT IN은 인덱스 풀 스캔 사용
MySQL 내장 함수
Null 값 비교 및 대체
- IFNULL() - NULL인지 비교하고, 맞으면 다른 값으로 대체
- ISNULL() - NULL인지 비교
현재 시각 조회
- NOW() - 하나의 SQL에서 항상 같은 값
- SYSDATE() - 호출되는 시점에 따라 결과값 달라져서 레플리카 서버에서 안정적으로 복제되지 못하고, 인덱스를 효율적으로 사용하지 못한다는 문제가 있다
=> NOW()를 사용하는 것이 좋다
날짜와 시간의 포맷
- DATE_FORMAT() - DATETIME 타입의 값을 원하는 형태의 문자열로 변환할 때
- STR_TO_DATE() - 문자열을 DATETIME 타입으로 변환
날짜와 시간의 연산
- 특정 날짜에서 시간을 더하거나 뺄 때 DATE_ADD(), DATE_SUB() 사용
타임스탬프 연산
- UNIX_TIMESTAMP(): 1970/01/01 부터 경과된 초의 수를 반환
- FROM_UNIXTIME(): 인자로 전달한 타임스탬프 값을 DATETIME으로 변환
- TIMESTAMP는 4바이트 숫자 타입으로 저장
문자열 처리
- RPAD(), LPAD(): 문자열 좌측 혹은 우측에 문자를 덧붙여 지정된 길이로 만듦
- RTRIM(), LTRIM(), TRIM(): 공백문자 제거
문자열 결합
- CONCAT(): 여러 개의 문자열을 하나의 문자열로 반환
- CONCAT_WS(): 문자열 연결할 떄 구분자 넣어줌
GROUP BY 문자열 결합
- GROUP_CONCAT(): GROUP BY 가 없는 SQL에서는 문자열 결합한 하나의 결과값만 만든다
- 지정된 칼럼의 값들을 연결하기 위해 제한적인 메모리 버퍼 공간을 사용한다
값의 비교와 대체
- CASE WHEN은 SWITCH 구문 같은 역할. 동등 연산자로 비교하거나, 표현식으로 비교
- CASE WHEN 절이 일치하는 경우에만 THEN 이하의 표현식이 실행된다
타입의 변환
- SQL에 입력된 모든 입력값은 문자열처럼 취급된다. 명시적 타입 변환이 필요하면 CAST() 이용
- CAST(): DATE, TIME, DATETIME, BINARY, CHAR, DECIMAL, SIGNED INTEGER, UNSIGNED INTEGER 변환 가능
- 문자열, 숫자, 날짜는 자동으로 변환하는 경우가 많다
- CONVERT(): CAST()와 같이 타입을 변환하는 용도와 문자열의 문자 집합을 변환하는 용도로 사
이진값과 16진수 문자열 변환
- HEX(): 이진값을 16진수 문자열로 변환
- UNHEX(): 16진수 문자열을 이진값으로 변환
암호화 및 해시 함수
- MD5(), SHA(), SHA2(): 비대칭형 암호화. 비밀번호같이 암호화 필요한 정보를 인코딩할 때 사용.
- 긴 데이터의 크기를 줄여서 인덱싱(해시) 하는 용도로도 사용
- 8.0 부터는 함수 기반의 인덱스를 생성하면 별도 칼럼을 추가하지 않아도 된다
SLEEP
- SLEEP(): 개발이나 디버깅 용도로 잠깐 대기하거나, 쿼리 실행을 오래 유지하고자 할 때 사용
- 레코드의 건수만큼 호출
벤치마크
- BENCHMARK(): 디버깅이나 간단한 함수 성능 테스트용으로 유용. 반복해서 수행할 횟수, 반복해서 실행할 표현식 입력받음
- 표현식을 SQL 클라이언트와 같은 도구로 여러번 실행하면 매번 쿼리 파싱이나 최적화, 테이블 잠금 비용 등이 소요되지만 벤치마크로 실행하면 단 1번의 네트워크, 쿼리 파싱 및 최적화 비용 소요
- 두 개의 동일 기능을 상대적으로 비교 분석하는 용도로 사용
IP 주소 변환
- INET_ATON(), INET_NTOA(): IPv4 주소를 문자열이 아닌 부호 없는 정수 타입에 저장할 수 있게 제공
- INET6_ATON(), INET6_NTOA(): IPv6 주소를 변환
JSON 포맷
- JSON_PRETTY()로 JSON 칼럼의 값을 읽기 쉽게 변환
JSON 필드 크기
- JSON_STORAGE_SIZE(): BSON(binary JSON) 포맷일 때 저장 공간의 크기 계산
JSON 필드 추출
- JSON_EXTRACT(): JSON에서 특정 필드의 값을 가져옴
- JSON_UNQUOTE(): 따옴표 없이 값만 가져옴
->,->>연산자를 대신 사용 가능
JSON 오브젝트 포함 여부 확인
- JSON_CONTAINS(): JSON 도큐먼트 또는 지정된 JSON 경로에 JSON 필드를 가지고 있는지 확인하는 함수
Metadata
Metadata
Assignees
Labels
No labels