mojh7 / real-mysql-study

:orange_book: Real MySQL 8.0 study
0 stars 0 forks source link

2023/01/05 ~ 2023/01/12 #36

Open mojh7 opened 1 year ago

mojh7 commented 1 year ago

다음 스터디

2023-01-12 목 pm 10:30

학습 범위

정리 범위

danbi5228 commented 1 year ago

11.4.3 WHERE 절의 비교 조건 사용 시 주의사항

11.4.3.1 NULL 비교

11.4.3.1 문자열이나 숫자 비교

11.4.3.3 날짜 비교

11.4.3.3.1 DATE 또는 DATETIME과 문자열 비교

11.4.3.3.2 DATE와 DATETIME의 비교

11.4.3.3.3 DATETIME과 TIMESTAMP 비교

mojh7 commented 1 year ago

11.4.3 WHERE 절의 비교 조건 사용 시 주의사항

11.4.3.4 Short-Circuit Evaluation

여러 개의 표현식이 AND 또는 OR 논리 연산자로 연결된 경우 선행 표현식의 결과에 따라 후행 표현식을 평가할지 말지 결정하는 최적화

boolean in_transaction;

if ( in_transaction && has_modified() ) {
    commit();
}

in_transaction 값이 TRUE이면 has_modified() 함수를 호출하고 FALSE 이면 has_modified() 결과에 관계 없이 commit()이 실행되지 않는다


MySQL에서 Short-circuit Evaluation 이 쿼리의 성능에 어떻게 영향을 미치는가?

SELECT COUNT(*) FROM salaries;
# 결과 2844047

# 1번 조건
SELECT COUNT(*) FROM salaries
WHERE CONVERT_TZ(from_date, '+00:00', '+09:00')>'1991-01-01';
# 결과 2442943

# 2번 조건
SELECT COUNT(*) FROM salaries
WHERE to_date<'1985-01-01';
# 결과 0

1, 2번 조건은 모두 인덱스를 사용하지 못하기 때문에 풀 테이블 스캔

1번과 2번 조건을 AND로 연결한 3번째 쿼리의 결과는 0건이 될 것이다


WHERE 절에 나열되는 조건의 순서가 쿼리의 성능에 영향을 미칠까?

SELECT COUNT(*) FROM salaries
WHERE 1번 조건 AND 2번 조건;
# (0.73 sec)

SELECT COUNT(*) FROM salaries
WHERE 2번 조건 AND 1번 조건;
# (0.52 sec)

WHERE 절에서 1번 조건을 먼저 사용한 쿼리가 더 오래 걸렸다

1번 조건이 먼저 사용된 쿼리의 경우

2번 조건이 먼저 사용된 쿼리의 경우


하지만 WHERE 절의 조건 중에서 인덱스를 사용할 수 있는 조건이 있다면 short-circuit evaluation 과는 무관하게 MySQL 서버는 그 조건을 가장 최우선으로 사용한다

SELECT * FROM employees
WHERE last_name='Aamodt'
AND first_name='Matt';

last_name 칼럼은 인덱스를 사용할 수 없지만 first_name 칼럼은 인덱스를 효율적으로 사용할 수 있다

WHERE 절에 나열된 조건의 순서와 무관하게 MySQL 서버는 인덱스를 사용할 수 있는 조건을 먼저 평가한다

그래야만 employees 테이블의 ix_firstname(first_name) 인덱스를 이용해서 꼭 필요한 레코드만 빠르게 가져올 수 있다

그러고 나서 first_name 조건을 제외한 나머지 조건을 순서대로 평가한다


75p 상단에 있는 쿼리에서 EXIST (subquery) 부분은 GROUP BY ... HAVING ... 절을 가지고 있기 때문에 세미 조인 최적화를 활용할 수 없다

first_name 칼럼의 조건은 인덱스를 사용할 수 있으므로 최우선으로 인덱스를 사용해 필요한 데이터의 범위를 최소화 할 것이고

그 결과 에서 last_name ='Aamodt' 조건과 서브쿼리 조건을 만족하는 레코드만 걸러서 결과를 반환한다

이 때 WHERE 절에 서브쿼리 조건이 먼저 나열됐기 때문에 last_name 칼럼의 조건보다 EXISTS (subquery) 조건을 먼저 평가한다


75p~76p 쿼리에서 last_name 비교 조건이 먼저 나오는 1번 쿼리와 EXISTS (subquery) 조건이 먼저 나오는 2번 쿼리에서

1번 쿼리는 ix_firstname 인덱스를 통해 233건의 레코드를 가져온 다음 last_name 조건을 만족하는지를 먼저 평가했고 이 둘을 만족하는 레코드 1건에 대해 EXISTS (subquery) 조건의 만족 여부를 평가했다

2번 쿼리는 반대로 ix_firstname 인덱스를 통해 가져온 233건에 대해 복잡한 EXISTS (subquery) 조건을 평가하면서 상당히 많은 레코드를 읽고 쓰는 작업을 처리 했다


결론


11.4.4 DISTINCT

특정 컬럼의 유니크한 값을 조회할 때 사용

많은 사용자가 조인을 하는 경우 레코드가 중복해서 출력되는 것을 막기 위해 DISTINCT를 남용하는 경향이 있다

성능적인 문제도 있지만 쿼리의 결과가 의도한 바와 달라 질 수 있으니 주의


여러 테이블을 조인하는 쿼리에서 조인 조건에 따라 레코드가 몇 배씩 불어나기도하는데

각 테이블의 간의 조인이 1:1, 1:M 조인인지와 같이 업무적인 연결 조건을 이해하지 못하고 쿼리를 작성하는 경우

주로 DISTINCT가 남용하는 경우가 발생