BETWEEN, IN()
SELECT * FROM TCUSTOMERPERSONAL
WHERE CUSTNO BETWEEN 3 AND 5 AND NAME = "김";
SELECT * FROM TCUSTOMERPERSONAL
WHERE CUSTNO IN (3, 4, 5) AND NAME = "김";
/*
1번은 CUSTNO가 3에서 5인 레코드의 전체 범위를 다 비교하지만,
2번은 (3, "김"), (4, "김"), (5, "김")인 레코드만 비교하기 때문에 성능 차이가 생김
*/
❓ 둘이 왜 다른거죠..? 둘다 3,4,5 먼저 조회 하고 뒤에 조건 검색하니까 비교하는 레코드 수는 같은거 아닌가요..?
JSON
- JSON_PRETTY(doc) 제이슨 형태를 이쁘게 보여줌 (사용은 안해봄 ㅠ)
- JSON_EXTRACT(doc, “$.NAME”) 제이슨 형태의 NAME value 값을 가져옴 SELECT doc->“$.NAME” FROM TCUSTOMERPERSONAL 로 사용 할 수도 있음
그룹 인덱스
- 그룹 인덱스인 경우 WHERE 절의 순서와는 무관, 그룹 인덱스 칼럼들이 있는지가 중요
- GROUP BY 절에 명시된 컬럼의 순서가 인덱스를 구성하는 칼럼의 순서와 같은면 인덱스 사용 가능
- ORDER BY 절에 명시된 컬럼의 순서가 인덱스를 구성하는 칼럼의 순서와 같은면 인덱스 사용 가능
❓ 이거 그룹 인덱스 맞나요..? ㅋㅋ 여기 좀 어려웠습니다. 그룹 인덱스 일 때 이거 사용 하려면 순서 같게 하는게 맞는건지..?
NULL비교
- MySQL은 NULL 값이 포함된 레코드도 인덱스로 관리함 NULL을 하나의 값으로 인정해서 관리 한다는 뜻
- 쿼리에서 NULL인지 비교하려면 IS NULL, ‘<=>’ 연산자를 사용해야 함 (이 방법 말고는 칼럼의 값이 NULL인지 알 수 없음)
문자열, 숫자
- 문자열 칼럼, 숫자 칼럼을 비교할 때는 반드시 그 타입에 맞는 상숫값을 사용하는 것이 좋음
SELECT * FROM TCUSTOMERPERSONL WHERE PHONE = 01012345678;
# 칼럼 타입과 동일한 타입이라서 인덱스를 잘 탐
SELECT * FROM TCUSTOMERPERSONL WHERE NAME = "시진엽";
# 칼럼 타입과 동일한 타입이라서 인덱스를 잘 탐
SELECT * FROM TCUSTOMERPERSONL WHERE PHONE = "01012345678";
# PHONE 칼럼의 타입이 숫자라서 문자열 값을 숫자로 변환해서 비교하기 때문에 성능 저하 없음
SELECT * FROM TCUSTOMERPERSONL WHERE NAME = 01031203280
# NAME은 문자열 타입이라서 비교 값이 숫자라면 NAME 칼럼의 문자열을 숫자로 변환 후 비교 하기 때문에 인덱스를 제로 타지 못함
DATE, DATETIME
- DATE, DATETIME 데이터 형식은 문자열과 비교 시 문자열을 자동으로 DATE 형식으로 변환해서 비교를 수행함
- DATE, DATETIME 타입의 비교에서 타입 변환은 인덱스 사용 여부에 영향을 미치지 않기 때문에 성능보다는 쿼리의 결과에 주의해서 사용
WHERE 절의 순서
- WHERE 절의 나열된 조건을 순서대로 작업하는게 기본
- 인덱스를 사용 할 수 있는 조건이 있다면 해당 조건을 우선적으로 사용함
- 조건에 서브쿼리 조건과 일반 칼럼 조건을 사용한다면 순서를 일반 칼럼을 먼저 배치 후 서브 쿼리 조건을 사용하는 것이 좀더 효율적(상황에 맞게 사용)
- 정리 : 조건이 여러개 라면 인덱스 조건을 우선 사용 후 나머지는 순서대로 처리 하기 때문에 서브쿼리 같이 작업이 많거나 오래 걸리는 조건일 수록 뒷 쪽에 배치하여 적은 레코드 값을 사용하도록 하여 성능을 높힐 수 있음
LIMIT n
- LIMIT 특성 : 필요한 레코드 건수만 준비되면 즉시 쿼리를 종료함 LIMIT 5 ⇒ 상위 5건까지만 조회가 되면 작업을 멈춤(풀 스캔 X)
SELECT * FROM TCUSTOMERPERSONAL LIMIT 10;
# LIMIT이 없다면 풀 스캔하지만, 상위 10개가 검색되면 작업을 멈춤
SELECT * FROM TCUSTOMERPERSONAL GROUP BY FIRST_NAME LIMIT 10;
# GROUP BY 처리가 완료 된 후 10개만 가져옴, GROUP BY와 LIMIT은 함께 사용하면 효율이 안좋음
SELECT DISITINCT FIRST_NAME FROM TCUSTOMERPERSONAL LIMIT 10;
# 풀 스캔을 통해 레코드를 읽어오는 동시에 중복 작업(이시테이블)이 이루어지며, 유니크한 레코드가 10개가 되면 작업 중지
SELECT * FROM TCUSTOMERPERSONAL WHERE FIRST_NAME = "LEO" ORDER BY DATE LIMIT 10;
# WHERE 조건으로 조회 후 정렬을 수행하면서 10개가 되면 작업 중지
- 페이지네이션, 무한스크롤 구현 시 주의사항
SELECT * FROM TCUSTOMERPERSONAL LIMIT 0, 10;
SELECT * FROM TCUSTOMERPERSONAL LIMIT 200000, 10;
/*
LIMIT 200000, 10 은 테이블을 처음부터 읽으면서 200010 건을 조회 후 200000건은 버리고
10건만 가져오기 때문에 불필요한 리소스가 많이 들어감
정말 많은 양의 페이지네이션을 하게 된다면, WHERE 절을 이용하여 구현
조건에 가장 마지막에 조회한 데이터의 위치를 넣어 그 이후 부터 10개를 가져오도록 함
*/
SELECT * FROM TCUSTOMERPERSONAL WHERE CUSTOMERID > 123456 LIMIT 0, 10;
COUNT()
- WHERE 조건이 없는 COUNT(*) 쿼리는 실제 레코드 건수를 세어보지 않아도 빠르게 처리됨
- WHERE 조건이 있는 경우 조건에 맞게 스캔 후 건수를 카운트함
- InnoDB 스토리지 엔진을 사용하는 테이블의 경우 WHERE 조건이 없더라고 데이터나 인덱스를 읽고 나서 카운트 하기 때문에 데이터 양이 많은 곳에서 COUNT()를 할땐 주의가 필요함
- COUNT(*) 쿼리 사용시 ORDER BY, LEFT JOIN 같은 불필요 작업은 제거하는것이 성능상 좋음 (MySQL 8.0 부터 ORDER BY 구문은 무시함)