[데이터베이스] SQL 안티패턴

2024. 11. 7. 22:27·Database

SQL 안티패턴에 대해서 알아보자

농담곰 생각하는 짤

 

전체 조회

SELECT * FROM USERS -- 안티패턴
SELECT ID, NAME, EMAIL FROM USERS -- 권장
  • SELECT *는 불필요한 데이터 전송을 발생 시키고, 테이블 구조 변경 시 예기치 못한 오류가 발생할 수 있습니다. 필요한 컬럼만 명시적으로 지정해야합니다.

문자열 연결로 동적 쿼리 생성

-- 안티패턴
name = request.getParameter("name")
sql = "SELECT * FROM USER WHERE NAME = '"+name+"'"; --안티패턴

-- 권장
sql = "SELECT * FROM USER WHERE NAME = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1,name);
rs = pstmt.excuteQuery();
  • 문자열 연결로 동작 쿼리 생성하면 SQL 인젝션 공격에 취약합니다. prepareStatement 겉은 바인딩 방식을 사용하여 보안을 강화합니다.

잘못된 데이터 타입 사용

  • 데이터 타입을 잘못 사용하면 데이터의 정확성과 효율성이 떨어질 수 있습니다.
  • 예) 날짜나 시간을 문자열로 저장 → 시간 관련 함수를 사용할 수 없고 , 정렬 비교가 제대로 이루어지지 않음.
  • 숫자가 아닌 문자열로 저장 → 연산 집계가 불가능, 공간낭비가 이루어진다.

다중 칼럼 속성

  • 하나의 엔티티에 여러 개의 값을 칼럼으로 만들어 대응하는 것
  • 원하는 정보를 모든 칼럼을 확인 해야한다.
  • 중복되는 값을 예방하기 어렵다 (일관성)
  • 컬럼 하나 값 수정을 위헤 테이블 전체가 잠금될 수 있다.
-- 안티패턴 
CREATE TABLE member( 
	id INT PRIMARY KEY,
	name VARCHAR(10), 
  hobby1 VARCHAR(10), // 취미1
  hobby2 VARCHAR(10), // 취미2
  hobby3 VARCHAR(10), // 취미3
);

-- 권장
CREATE TABLE member (
  member_id INT PRIMARY KEY,
  name VARCHAR(10), 
  hobby_id INT FOREIGN KEY REFERENCES hobby(hobby_id)
);

CREATE TABLE hobby (
  hobby_id INT PRIMARY KEY,
  name VARCHAR(10)
);

 

과도한 조인 (Excessive Joins)

  • 너무 많은 테이블을 조인하면 쿼리 성능이 크게 저하됩니다.
  • 해결 : 필요한 조인을 줄이고, 데이터를 미리 캐싱하거나 데이터를 분리하여 사용한다.

FLOAT 데이터형 사용

  • 정수나 정확한 숫자를 저장할 때 FLOAT 사용
  • 지수부를 2진수로 표현하기 때문에 10진수 값을 나타낼 때 어느정도의 오차가 존재한다.
  • 초반에 적었던 오차가 예를 들어 이자 복리계산 때에는 곱셈을 여러번 해서 커지게 된다.
  • 해결법 : NUMERIC 또는 DECIMAL 데이터형을 사용하자.
    • 둘은 고정 소수점을 사용한다.

NULL에 대한 오해

  • 결손값을 채우려고 NULL을 일반값으로 사용하는 경우
  • NULL은 특수한 상태로 0, 빈 문자열, FALSE와 같지 않다.
  • NULL은 NULL이기 때문에 비교대상으로 사용할 수 없다.
  • NULL 값을 의도적으로 사용하고, 기본 값 대신 NULL 여부로 상태를 나타내도록 한다.

무결성 제약 조건 무시

  • 두 테이블 간의 오래 키 (Foreign key) 관계를 정의하지 않는 경우
-- 안티패턴
CREATE TABLE Users (
    user_id INT PRIMARY KEY,
    user_name VARCHAR(50)
);

CREATE TABLE Orders (
    order_id INT PRIMARY KEY,
    user_id INT,  -- Foreign Key가 정의되지 않음
    order_date DATE
);

--권장 
CREATE TABLE Orders (
    order_id INT PRIMARY KEY,
    user_id INT,
    order_date DATE,
    FOREIGN KEY (user_id) REFERENCES Users(user_id)
);
  • 존재 하지 않는 user_id를 실수로 추가할 수 있음. 데이터 무결성 문제를 초래한다.

인덱스 남발

  • 모든 컬럼에 인덱스를 추가하는 경우
  • 인덱스는 검색 성능을 높이지만 삽입, 수정, 삭제 시 인덱스도 갱신되어야 하므로 성능이 저하될 수 있음
  • 해결 : 자주 조회하는 컬럼에만 인덱스를 추가하여, 나머지 컬럼은 인덱스를 피합니다.

과도한 서브쿼리 사용

  • 중첩된 서브쿼리를 사용하는 경우. 서브쿼리가 많아 질 수록 쿼리 성능이 저하되며, 특히 데이터 양이 많을 때 불필요한 서브쿼리가 성능에 악영향을 줌.
  • 해결 : JOIN을 사용해 동일한 결과를 얻고, 성능을 개선한다.

하드코딩된 값을 사용

SELECT * FROM Orders WHERE status = 'stop';
SELECT * FROM Orders WHERE status = :status;
  • 하드코딩된 값 대신 변수화된 쿼리나 상수를 사용해 유지보수를 쉽게 한다.

 

참고 : http://happily70.dothome.co.kr/?p=682

https://velog.io/@yoonuk/데이터베이스-SQL-안티-패턴

'Database' 카테고리의 다른 글

[데이터베이스] B-Tree 인덱스와 B+Tree 인덱스  (0) 2024.11.13
[데이터베이스] 순차 I/O와 랜덤 I/O  (2) 2024.11.12
[데이터베이스] Pagination 구현 SQL  (1) 2024.11.08
[데이터베이스]Table 용어 정리  (0) 2024.10.28
[데이터베이스]DB와 DBMS 란?  (1) 2024.10.28
'Database' 카테고리의 다른 글
  • [데이터베이스] 순차 I/O와 랜덤 I/O
  • [데이터베이스] Pagination 구현 SQL
  • [데이터베이스]Table 용어 정리
  • [데이터베이스]DB와 DBMS 란?
슈가솔트
슈가솔트
  • 슈가솔트
    소금과 설탕
    슈가솔트
  • 전체
    오늘
    어제
    • 분류 전체보기 (31)
      • Database (10)
      • TDD (11)
      • Java (0)
      • 회고 (1)
      • 코테 (1)
      • CS (8)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    반정규화
    데이터베이스
    랜덤i/o
    순차i/o
    DB
    mocking
    db데드락
    오블완
    컨트롤러테스트
    CQRS
    튜플
    릴레이션
    아키텍처레이어
    Mockito
    testcode
    티스토리챌린지
    TDD
    B+Tree
    spring rest docs
    asciidoc
    pagination
    stubbing
    테스트작성
    db #datebase #dbms
    통합테스트
    백엔드
    db회복
    단위테스트
    인덱스
    sql 안티패턴
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
슈가솔트
[데이터베이스] SQL 안티패턴
상단으로

티스토리툴바