흔히들 아는 Insert 문이란 다음의 형식과 같다.
insert into {table} (column) values (data)
하지만 PK가 겹친다면 duplicate 에러가 나버린다.
중복된다는 뜻.
그를 위해 ORM에서는 Upsert의 기능이 있다.
Insert
하고, 만약 있다면 Update
하는 것이다.
그를 위해 먼저 Select
을 돌린다.
2개의 구문이 나간다는 것이다.
비효율적이지않은가?
자세하게는 적지않겠다.
나보다 더 잘 정리한 사람들이 있으니
들어가기 귀찮을테니 대략적으로 적자면
Insert INTO person(name, score) Values("Sunrabbit", 123)
ON DUPLICATE KEY UPDATE score = score + VALUES(score);
다음과 같이 이미 있다면, 원래 있던 값에 1을 더한다는 것이다.
그냥 score
로 접근한다면 기존 테이블에 있는 값을, VALUES(score)
로 접근한다면 Insert
문에 있는 score
값에 접근이 된다.
즉 기존 값에 추가가 된다는 것이다.
왜 이런 방식을 사용하냐면, 데이터의 무결성과 정합성을 위함이다.
SELECT
과 UPDATE
, INSERT
를 묶어 Upsert
를 만들어 하나의 트랜잭션으로 하면 되느냐라는 이야기가 있을 수 있다.
그렇다면 레이스컨디션은 어떻게 버틸 것인가?
기존의 값에 추가를 하는 이 방식으로 이를 해결 할 수 있으니 얼마나 좋은가.
기존 Node
진영의 ORM
인 Prisma
의 Upsert
는 SELECT
후 UPDATE
를 하던 INSERT
를 하는 방식이다.
그리고 Mikro ORM
의 경우 Insert
구문 뒤에 merge
기능을 통해 해결하는데, 이는 onConflict
이 났을 경우다.
knex
라는 SQL Query builder를 이용한 것이다.
끗
추가적으로
PostgreSQL
에서는ON CONFLICT DO UPDATE
를 쓴다.INSERT INTO {table} values ({data}) ON CONFLICT (id) DO UPDATE SET column_1 = excluded.column_1, column_2 = excluded.column_2;
때로는 ORM보다 SQL이 더 직관적이고 편하다.