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;
- 하드코딩된 값 대신 변수화된 쿼리나 상수를 사용해 유지보수를 쉽게 한다.
'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 |