Make Be BackEnd

[MySQL] UPDATE 본문

DB

[MySQL] UPDATE

Initsave 2024. 8. 24. 12:36

 

UPDATE 방식은 여러가지가 있다. 최근 본 프로젝트에서 UPDATE문을 JOIN으로 하는것을 보고 너무 신기해서 UPDATE에 대해 좀더 알아보기로 했다. 일반적으로 사용하는 UPDATE ~ SET ~ WHERE, 파라미터로 값을 받아서 처리하는 방식 외에도 많은 방식으로도 있는 것을 알게 되었다.
 

1. 단일 테이블 업데이트

       기본적으로 사용하는 업데이트

UPDATE users
SET status = 'inactive'
WHERE last_login < '2023-01-01';

 

2. CASE 문을 사용한 조건부 업데이트
        'CASE' 문을 사용한 업데이트

UPDATE users
SET status = CASE 
    WHEN last_login < '2023-01-01' THEN 'inactive'
    WHEN last_login >= '2023-01-01' AND last_login < '2023-06-01' THEN 'semi-active'
    ELSE 'active'
END;

 

3. 변수 사용

        'SET'으로 변수를 설정해서 업데이트

UPDATE users
SET status = CASE 
    WHEN last_login < '2023-01-01' THEN 'inactive'
    WHEN last_login >= '2023-01-01' AND last_login < '2023-06-01' THEN 'semi-active'
    ELSE 'active'
END;

 

4. 데이터 복사 후 대체(REPLACE 또는 INSERT INTO SELECT)

        'INSERT INTO SELECT' , 'REPLACE'를 사용해서 데이터 복사,교체 업데이트
          (대규모로 데이터를 업데이트, 테이블 재구조화 할때 좋다)

INSERT INTO users_backup (id, name, status)
SELECT id, name, 'inactive'
FROM users
WHERE last_login < '2023-01-01';

REPLACE INTO users SELECT * FROM users_backup;

 

5. 트리거(Trigger) 사용

       트리거는 테이블 데이터가 변경되면 변경된 테이블과 연결된 테이블의 데이터도 변경시켜준다. 
        (복잡한 데이터 일관성을 유지하는데 좋다.)

CREATE TRIGGER update_user_status
AFTER INSERT ON orders
FOR EACH ROW
BEGIN
    UPDATE users
    SET total_orders = total_orders + 1
    WHERE users.id = NEW.user_id;
END;

        

6. 멀티 테이블 업데이(Muti-Table Update)

        두개 이상의 테이블을 동시에 업데이트, 조인된 여러 테이블에 대해 한번에 업데이트가 필요한 경우

UPDATE users, orders
SET users.status = 'inactive', orders.status = 'cancelled'
WHERE users.id = orders.user_id
AND users.last_login < '2023-01-01';

 

7. 서브쿼리 업데이트

UPDATE users
SET total_orders = (
    SELECT COUNT(*)
    FROM orders
    WHERE orders.user_id = users.id
)
WHERE users.status = 'active';

 

 

8. JOIN 업데이트

UPDATE users u
JOIN (
    SELECT user_id, COUNT(*) AS order_count
    FROM orders
    GROUP BY user_id
) o ON u.id = o.user_id
SET u.total_orders = o.order_count
WHERE u.status = 'active';

        

성능적으로는 서브쿼리보다는 JOIN쿼리 방식을 더 선호하고 쿼리가 더 직관적이고 유지하기 쉽다고 한다. 하지만 웹서비스 같은 OLTP환경에서는 데드락을 유발하기도 하기 때문에 사용 하는 환경에 따라서 어느쪽에 더 좋은지 좀더 고민하고 사용하는것이 좋지 않을까..?

 

서브쿼리 vs. JOIN을 사용하는 이유

1. 성능: 서브쿼리는 각 행에 대해 서브쿼리를 실행하는 경우가 많아 성능이 저하될 수 있습니다. 반면, JOIN을 사용하면 조인된 테이블의 데이터를 한 번에 가져와 업데이트하므로 성능이 향상될 수 있습니다.

2. 가독성: 서브쿼리를 사용하면 쿼리가 복잡해질 수 있지만, JOIN을 사용하면 쿼리가 더 직관적이고 읽기 쉬워집니다. 특히 여러 테이블을 조인하여 다양한 조건을 적용하는 경우, JOIN이 더 명확한 표현 방법이 될 수 있습니다.

3. 유연성: JOIN을 사용하면 여러 테이블에서 데이터를 쉽게 결합하고, 결합된 데이터를 기반으로 원하는 필드를 업데이트할 수 있습니다. 이는 서브쿼리를 사용할 때보다 더 유연하게 조건을 설정할 수 있게 해줍니다

출처 : chatgpt

 

JO IN UPDATE는 조인되는 모든 테이블에 대해 읽기 참조만 되는 테이블은 읽기 잠금이 걸리고, 칼럼이 변경되는 테이블은 쓰기 잠금이 걸린다. 그래서 JO IN UPDATE 문장이 웹 서비스 같은 OLTP 환경에서는 데드락을 유발할 가능성이 높으므로 너무 빈번하게 사용하는 것은 피하는 것이 좋 다. 하지만 배치 프로그램이나 통계용 UPDATE 문장에서는 유용하게 사용할 수 있다.

출처 : Real My SQL 8.0 2

 

 

 

 

++

UPDATE JOIN , DEADLOCK


UPDATE JOIN과 UPDATE 서브쿼리를 비교할 때, 성능과 동시성 제어(예: 데드락 회피) 사이에서 균형을 잡아야 합니다. 상황에 따라 각각의 접근 방식이 적합할 수 있으며, 아래와 같은 내용을 고려할 필요가 있습니다.

1. UPDATE JOIN vs. UPDATE 서브쿼리
- UPDATE JOIN: 일반적으로 두 개 이상의 테이블을 조인하여 업데이트할 때 사용됩니다. 한 번의 쿼리로 여러 테이블     의 데이터를 조회하고 동시에 업데이트할 수 있어, 단일 쿼리로 많은 작업을 처리할 수 있습니다. 이는 성능 측면에       서 이점이 될 수 있습니다.
- UPDATE 서브쿼리: 주로 서브쿼리를 사용하여 특정 조건에 맞는 데이터를 업데이트할 때 사용됩니다. 이는 좀 더 직    관적일 수 있고, 복잡한 로직을 처리하는 데 유리합니다.

2. 데드락 발생 가능성
- UPDATE JOIN은 조인되는 테이블들이 동시에 잠금을 걸게 되며, 이로 인해 데드락(Deadlock)이 발생할 가능성이
   있습니다. 특히, 여러 테이블에서 동시에 데이터에 접근하고 잠금을 걸 때, 서로 교착 상태에 빠질 위험이 있습니다.
- UPDATE 서브쿼리는 일반적으로 단일 테이블을 타겟으로 하는 경우가 많아, 잠금이 상대적으로 덜 발생할 수 있습니
   다. 그러나, 서브쿼리 자체가 복잡하거나 많은 데이터를 처리할 경우에도 잠금과 성능 문제가 발생할 수 있습니다.

3. 데드락 회피 및 성능 최적화 전략
1. 트랜잭션의 순서 조정: 동일한 테이블에 접근하는 트랜잭션들이 일정한 순서로 잠금을 걸도록 설계하여 데드락을 방지합니다.
2. 잠금 범위 최소화: UPDATE JOIN을 사용하는 경우, 업데이트하는 범위를 좁혀 잠금 시간을 최소화합니다.
3. 트랜잭션 분할: 큰 트랜잭션을 작은 트랜잭션으로 나누어 한 번에 잠기는 레코드 수를 줄입니다.
4. 인덱스 활용: UPDATE JOIN에서 인덱스를 잘 활용하여 잠금 범위를 줄이고, 성능을 향상시킵니다.
5. LOCK TIMEOUT 설정: 데드락 발생 시 빠르게 타임아웃을 설정하여 다른 작업이 수행될 수 있도록 합니다.
6. 트랜잭션 격리 수준 조정: MySQL의 경우 READ COMMITTED 또는 REPEATABLE READ 격리 수준을 사용해 데드락 발생 가능성을 줄일 수 있습니다.

결론

- 성능을 우선: 만약 성능이 매우 중요한 웹서비스라면, UPDATE JOIN을 사용하면서 잠금 범위를 최소화하고 트랜잭션 순서를 조정하여 데드락 가능성을 줄이는 것이 좋습니다.
- 안정성을 우선: 데드락이 빈번하게 발생하는 환경이라면, UPDATE 서브쿼리를 사용하는 것이 좋을 수 있습니다. 이는 잠금이 덜 발생하도록 하고, 트랜잭션을 좀 더 안정적으로 처리할 수 있습니다.

상황에 따라 두 방법을 적절히 사용하고, 필요에 따라 데드락 회피 전략을 적용하는 것이 중요합니다.

출처 : chatgpt

'DB' 카테고리의 다른 글

Tibero(티베로)  (0) 2024.08.31
[MySQL] 계층 쿼리 (hierarchical query)  (0) 2024.05.23
[ORACLE] 계층 쿼리 (hierarchical query)  (0) 2024.05.23
[DBeaver] 디비버 설치(DB 셋팅)  (0) 2024.04.30
[H2] H2 Database  (0) 2023.09.18