반응형
Ant_U
DBA 개미
Ant_U
전체 방문자
오늘
어제
  • 분류 전체보기 (271)
    • AWS (3)
    • C# (1)
    • SQL (245)
      • MYSQL (195)
      • MSSQL (50)
    • 자격증 (20)
      • SQLD (12)
      • SQLP (8)

인기 글

최근 글

250x250
hELLO · Designed By 정상우.
Ant_U

DBA 개미

[MySQL] 논리 연산자 완벽 가이드: AND, OR, NOT 제대로 사용하기
SQL/MYSQL

[MySQL] 논리 연산자 완벽 가이드: AND, OR, NOT 제대로 사용하기

2026. 2. 3. 11:08
728x90
반응형

 

MySQL의 AND, OR, NOT 연산자의 작동 원리, 우선순위 규칙, 그리고 쿼리 성능에 미치는 영향을 다룹니다. 초보자부터 전문가까지 반드시 알아야 할 데이터 필터링의 핵심을 정리했습니다.


들어가며

데이터베이스 관리 시스템(DBMS)에서 데이터를 저장하는 것만큼 중요한 것이 바로 원하는 데이터를 정확하게 추출하는 것입니다. 수백만 건의 데이터 중에서 비즈니스 로직에 맞는 행(Row)만을 골라내기 위해 우리는 WHERE 절을 사용하며, 이때 필터링 조건을 정교하게 결합해 주는 도구가 바로 논리 연산자(Logical Operators)입니다.

MySQL을 사용하는 개발자라면 누구나 SELECT * FROM table WHERE condition... 형태의 쿼리를 작성해 본 경험이 있을 것입니다. 하지만 AND와 OR가 복합적으로 사용될 때의 우선순위 문제나, NOT 연산자가 인덱스 성능에 미치는 영향을 간과하여 의도치 않은 버그를 만들거나 쿼리 속도를 저하시키는 경우가 종종 발생합니다.

이 글에서는 가장 기본적이면서도 실수하기 쉬운 AND, OR, NOT 연산자의 정확한 동작 방식과 실행 순서, 그리고 성능 최적화를 위한 팁을 정리해 드립니다.


1. 기본 개념: 교집합, 합집합, 그리고 부정

가장 먼저 세 가지 연산자의 기본 동작을 명확히 정의해 보겠습니다.

AND 연산자 (교집합)

AND는 나열된 모든 조건이 참(True)이어야만 결과에 포함됩니다. 조건이 늘어날수록 결과 집합의 크기는 줄어들거나 같게 유지됩니다. 즉, 데이터를 좁혀나가는(Narrowing) 역할을 합니다. 예를 들어, 부서가 '개발팀'이면서 동시에 직급이 '과장'인 사원을 찾을 때 사용합니다.

OR 연산자 (합집합)

OR는 나열된 조건 중 하나라도 참이면 결과에 포함됩니다. 조건이 늘어날수록 결과 집합의 크기는 늘어나거나 같게 유지됩니다. 즉, 데이터를 확장하는(Widening) 역할을 합니다. 예를 들어, 부서가 '개발팀'이거나 혹은 '디자인팀'인 모든 사원을 찾을 때 사용합니다.

NOT 연산자 (부정)

NOT은 바로 뒤에 오는 조건의 참/거짓 결과를 뒤집습니다. 참은 거짓으로, 거짓은 참으로 변환합니다. 예를 들어, 부서가 '영업팀'이 아닌 사원들을 찾을 때 사용합니다.


2. 연산자 우선순위의 함정 (Operator Precedence)

SQL을 처음 접하는 주니어 개발자뿐만 아니라 숙련된 개발자도 복잡한 쿼리를 작성하다 보면 흔히 저지르는 실수가 바로 연산자 우선순위 문제입니다.

MySQL에서 AND 연산자는 OR 연산자보다 우선순위가 높습니다. 수학에서 덧셈보다 곱셈을 먼저 계산하는 것과 같은 원리입니다.

다음 쿼리를 예로 들어보겠습니다.

SELECT * FROM products WHERE category = 'Electronics' OR category = 'Computers' AND price >= 1000;

개발자의 의도는 "카테고리가 전자제품이거나 컴퓨터인 상품 중에서, 가격이 1000 이상인 것"을 찾고 싶었을 것입니다. 하지만 MySQL은 이 쿼리를 다음과 같이 해석합니다.

  1. category = 'Computers' AND price >= 1000 (이 조건을 먼저 묶어서 처리)
  2. category = 'Electronics' (그 다음 이 조건과 OR 연산)

결과적으로 "컴퓨터 카테고리의 1000 이상인 상품"과 "가격 상관없이 모든 전자제품"이 조회되어 버립니다. 의도와 전혀 다른 데이터가 추출되는 것입니다.

이를 해결하는 유일하고 확실한 방법은 괄호 ()를 사용하는 것입니다.

SELECT * FROM products WHERE (category = 'Electronics' OR category = 'Computers') AND price >= 1000;

괄호는 모든 연산자보다 우선순위가 가장 높습니다. 따라서 복합 조건을 사용할 때는 괄호를 명시적으로 사용하여 가독성을 높이고 논리적 오류를 방지하는 습관을 들이는 것이 좋습니다.


3. NULL 처리와 3-valued Logic (3치 논리)

프로그래밍 언어의 불리언(Boolean)은 참과 거짓 두 가지만 존재하지만, 데이터베이스에는 NULL이라는 제3의 상태가 존재합니다. NULL은 "값이 없음" 또는 "알 수 없음(Unknown)"을 의미합니다.

이로 인해 논리 연산 결과가 예상과 다를 수 있습니다.

AND 연산: 1 AND NULL의 결과는 NULL(알 수 없음)입니다. 조건 중 하나가 거짓(0)이면 결과는 0이지만, 하나가 참이고 나머지가 NULL이면 전체 결과는 확정할 수 없기 때문입니다.

OR 연산: 1 OR NULL의 결과는 1(참)입니다. 조건 중 하나만 참이면 나머지가 무엇이든 참이기 때문입니다. 하지만 0 OR NULL은 NULL이 됩니다.

NOT 연산: NOT NULL의 결과는 여전히 NULL입니다. 알 수 없는 값을 부정해도 여전히 알 수 없기 때문입니다.

따라서 데이터 필터링 시 컬럼에 NULL이 포함될 가능성이 있다면, IS NULL 또는 IS NOT NULL 조건을 명시적으로 함께 처리해야 의도한 데이터를 정확히 가져올 수 있습니다.


4. 성능과 인덱스 활용 (Performance Considerations)

쿼리의 정확성만큼이나 중요한 것이 성능입니다. 대용량 데이터베이스에서 논리 연산자를 어떻게 사용하느냐에 따라 쿼리 속도가 천차만별로 달라질 수 있습니다.

OR 연산자와 인덱스 풀 스캔

일반적으로 AND 조건은 인덱스를 타고 데이터를 빠르게 좁혀나가는 데 유리합니다. 반면 OR 조건은 주의가 필요합니다. 만약 조건 컬럼 중 하나라도 인덱스가 걸려있지 않다면, MySQL은 데이터를 찾기 위해 테이블 전체를 스캔(Full Table Scan)해야 할 수도 있습니다.

MySQL 5.0 이상부터는 index merge 최적화 기능이 도입되어, OR 조건으로 연결된 서로 다른 컬럼들이 각각 인덱스를 가지고 있다면 이를 병합하여 처리할 수 있습니다. 하지만 여전히 단일 인덱스나 복합 인덱스를 사용하는 AND 조건보다는 성능이 떨어질 수 있습니다.

NOT 연산자와 인덱스

부정 연산자(!=, <>, NOT IN 등)는 일반적으로 인덱스를 효율적으로 사용하기 어렵습니다. "특정 값이 아닌 것"을 찾는 작업은 B-Tree 인덱스 구조상 데이터의 대부분을 읽어야 하는 경우가 많기 때문입니다. 따라서 대용량 테이블에서 NOT 조건을 사용할 때는 쿼리 실행 계획(EXPLAIN)을 확인하여 비효율적인 스캔이 발생하는지 점검해야 합니다.


결론 및 실무 팁

MySQL의 AND, OR, NOT은 단순해 보이지만, 데이터 무결성과 쿼리 성능을 결정짓는 중요한 요소입니다. 오늘 다룬 내용을 요약하며 실무에서 바로 적용할 수 있는 팁을 정리합니다.

핵심 요약 및 실무 팁

  1. 괄호 사용을 생활화하세요: AND와 OR가 섞여 있다면, 우선순위를 기억하려 애쓰기보다 괄호로 명확하게 묶어주는 것이 가독성과 정확성 면에서 훨씬 좋습니다.
  2. NULL의 함정을 피하세요: 컬럼이 NOT NULL 제약조건이 없다면, NULL 값에 대한 논리 연산 결과(Unknown)를 항상 염두에 두어야 합니다.
  3. OR 대신 UNION을 고려하세요: 복잡한 OR 조건으로 인해 인덱스를 제대로 타지 못해 쿼리가 느려진다면, 쿼리를 두 개로 나누어 UNION ALL로 결합하는 것이 성능상 유리할 때가 많습니다.
  4. 숏서킷(Short-Circuit) 평가 활용: AND 조건에서는 가장 걸러지는 데이터가 많은(False가 될 확률이 높은) 조건을, OR 조건에서는 참이 될 확률이 높은 조건을 앞쪽에 배치하면 미세하지만 성능 이점을 얻을 수도 있습니다. (단, MySQL 옵티마이저가 자동으로 순서를 재배치할 수 있으므로 절대적인 규칙은 아닙니다.)

공식 문서 링크

더 깊이 있는 내용과 버전에 따른 상세한 동작 방식은 아래 공식 문서를 참고하시기 바랍니다.

MySQL 8.0 Reference Manual - Logical Operators https://dev.mysql.com/doc/refman/8.0/en/logical-operators.html

728x90
반응형

'SQL > MYSQL' 카테고리의 다른 글

[MySQL] LIKE 연산자 활용법과 성능 최적화 가이드 (인덱스 활용 및 주의사항)  (0) 2026.02.05
[MySQL] WHERE 절 완전 정복: 기본 문법부터 8.0 최적화 팁까지  (0) 2026.01.30
[MySQL] DISTINCT: 중복된 데이터를 세련되게 처리하는 기술 (기초부터 성능 최적화까지)  (0) 2026.01.29
[MySQL] 백틱(`)의 역할과 올바른 사용법: 언제 써야 하고, 언제 피해야 할까?  (0) 2026.01.28
[MySQL] 습관적으로 쓴 SELECT * 가 당신의 DB를 느리게 만드는 이유 (feat. 실행 계획 분석)  (0) 2026.01.27
[MySQL] 에러 핸들링의 숨은 조력자: SHOW ERRORS 문 완벽 가이드  (0) 2026.01.26
[MySQL] 스토리지 엔진 확인의 첫걸음: SHOW ENGINES 문법 완벽 가이드  (0) 2026.01.22
[MySQL] SHOW ENGINE 문법 정복: SHOW ENGINE INNODB STATUS로 잠금·데드락·버퍼 이슈 읽어내기  (1) 2026.01.20
    'SQL/MYSQL' 카테고리의 다른 글
    • [MySQL] LIKE 연산자 활용법과 성능 최적화 가이드 (인덱스 활용 및 주의사항)
    • [MySQL] WHERE 절 완전 정복: 기본 문법부터 8.0 최적화 팁까지
    • [MySQL] DISTINCT: 중복된 데이터를 세련되게 처리하는 기술 (기초부터 성능 최적화까지)
    • [MySQL] 백틱(`)의 역할과 올바른 사용법: 언제 써야 하고, 언제 피해야 할까?
    Ant_U
    Ant_U

    티스토리툴바