같은 값으로 행을 업데이트하면 실제로 행이 업데이트됩니까?


28

성능 관련 질문이 있습니다. 이름이 Michael 인 사용자가 있다고 가정하겠습니다. 다음 쿼리를 수행하십시오.

UPDATE users
SET first_name = 'Michael'
WHERE users.id = 123

쿼리가 동일한 값으로 업데이트 되더라도 실제로 업데이트를 실행합니까? 그렇다면 어떻게됩니까?


1
명령문을 실행하면서 동시에 실행되지 않을 것으로 예상하는 이유는 무엇입니까?
Max Vernon

@MaxVernon Ruby on Rails의 ORM은 레코드를 업데이트하지 않으므로 PostgreSQL이 동일한 작업을 수행했는지 궁금합니다.
OneSneakyMofo

1
Ruby on Rails가 그렇게하고 있다면 행을 업데이트 해야하는지 확인하기 위해 먼저 선택을하고있을 것입니다.
Max Vernon

x-posted
so

답변:


35

Postgres 의 MVCC 모델 로 인해 SQL 규칙 에 따라 절 에서 제외되지 않은 모든 행에 UPDATE대해 새 행 버전을 작성합니다 .WHERE

수행 직간접 적 성능에 어느 정도 상당한 영향을 미친다. "빈 업데이트"는 다른 업데이트와 동일한 행당 비용을 갖습니다. 다른 업데이트와 마찬가지로 트리거 (있는 경우)를 발생 시키며 WAL 로그 를 작성해야하며 테이블을 부 풀리는 데드 행을 생성하여 VACUUM다른 업데이트와 마찬가지로 나중에 더 많은 작업을 수행합니다 .

관련된 열이 변경되지 않은 항목 및 TOASTed 열 은 동일하게 유지 될 수 있지만 업데이트 된 모든 행에 해당됩니다. 관련 :

빈 업데이트는 제외하는 것이 좋습니다 (실제로 발생할 가능성이있는 경우). 질문에 테이블 정의를 제공하지 않았습니다 (항상 좋은 생각입니다). 우리는 first_nameNULL 일 수 있다고 가정 해야합니다 ( "이름"에 놀라지 않을 것입니다). 따라서 쿼리는 NULL 안전 비교 를 사용해야 합니다 .

UPDATE users
SET    first_name = 'Michael'
WHERE  id = 123
AND   first_name IS DISTINCT FROM 'Michael';

경우 first_name IS NULL업데이트 이전에 테스트는 first_name <> 'Michael'NULL로 평가 것이며, 이러한 업데이트에서 행을 제외한다. 부적절한 오류. 열이 정의되어 있으면 간단한 동등성 검사를 사용하십시오. 약간 저렴하기 때문입니다.NOT NULL

관련 :


1
Indexes entries and TOASTed columns where none of the involved columns are changed can stay the same그러나 새로운 행 위치를 가리 키도록 업데이트하지 않아도됩니까?
dvtan

1
@dtgq : 인덱스가 기존 위치를 계속 가리킬 수있는 HOT 업데이트가 아니라 힙 가져 오기가 HOT 체인을 통과하여 라이브 튜플을 가져와야합니다. 위의 자세한 설명에 대한 링크를 추가했습니다.
Erwin Brandstetter

1
MVCC는 새로운 튜플을 작성하기 위해 noop 업데이트를 요구합니까?
jberryman

@jberryman : 잘 모르겠습니다. 어느 쪽이든, 새로운 질문으로 질문하십시오 . 컨텍스트를 위해 항상이 링크에 연결할 수 있습니다. 그리고 당신은 여기에 의견을 남길 수 있습니다.
Erwin Brandstetter

2
@jberryman : 실제로하지 않습니다 알고 프로젝트가 이런 식으로 갔다 이유를. 그것은 오래 전에 설립되었습니다. 그러나 모든 행의 동등성을 검사하고 변경되지 않은 행에 대해 별도의 코드 경로를 갖는 것이 불필요하게 비싸다고 가정 합니다. 트랜잭션 ID의 처리는 더 복잡 할 것입니다- rollback스냅 샷 처리, 잠금 관리, WAL을 위한 특수 케이스
Erwin Brandstetter

4

ORM은 Ruby on Rail의 지연된 실행을 제공하여 레코드가 변경 (또는 변경되지 않은)으로 표시 한 다음 필요하거나 호출 될 때 변경 사항을 데이터베이스에 제출합니다.

PostgreSQL은 데이터베이스이며 ORM이 아닙니다. 새 값이 쿼리의 업데이트 된 값과 같은지 확인하는 데 시간이 걸리면 성능이 저하되었을 수 있습니다.

따라서 새 값과 같은지 여부에 관계없이 값을 업데이트합니다.

이것을 막으려면 Max Vernon과 같은 코드를 그의 대답에서 사용할 수 있습니다.


2

당신은 단순히 where절에 추가 할 수 있습니다 :

UPDATE users
SET first_name = 'Michael'
WHERE users.id = 123
    AND (first_name <> 'Michael' OR first_name IS NULL);

경우 first_name로 정의 NOT NULLOR first_name IS NULL일부를 제거 할 수있다.

조건:

(first_name <> 'Michael' OR first_name IS NULL)

(Erwin의 답변에서) 더 우아하게 쓸 수 있습니다.

first_name IS DISTINCT FROM 'Michael'

열이 NULL 일 수 있는지 알지 못하면 부적절한 버그가 발생할 수 있습니다.
Erwin Brandstetter

1
@ ErwinBrandstetter 나는 대답을 업데이트하고 있었다-그리고 나는 코멘트와 당신의 대답을 보았다!
ypercubeᵀᴹ

과에 대한 코멘트 - 편집, @ypercube 감사 NULL@erwin
최대 버논

1

데이터베이스 관점에서

귀하의 질문에 대한 답변은 예입니다. 업데이트가 진행됩니다. 데이터베이스는 이전 값을 확인하지 않고 새 값만 설정합니다.

메모리에서 발생하고 (커밋이 발행 된 후에 만 ​​데이터 파일에 기록됨) 성능에는 문제가되지 않습니다.

ORM 관점에서

일반적으로 데이터베이스의 단일 행을 나타내는 Object가 있습니다 (이보다 훨씬 복잡 할 수 있지만 단순하게 유지합시다). 이 객체는 메모리에서 (앱 서버 수준에서) 관리되며 해당 객체의 최신 커밋 된 버전 만 실제로 특정 시점에 데이터베이스로 만듭니다.

그것은 다른 행동을 설명 할 수 있습니다.

이제 화물선을 3D 프린터와 비교하지 마십시오. 화물선을 사용하여 3D 프린터를 보낼 수 있다고해서 서로 비교할 수있는 것은 아닙니다.

즐겨!

이것이 몇 가지 개념을 명확히하기를 바랍니다.


4
성능 입니다 및 문제. 모든 업데이트는 디스크 (로그 및 테이블)에 작성해야합니다.
ypercubeᵀᴹ

사용하는 실제 RDBMS에 따라 다릅니다. 그러나 대부분은 모든 단일 업데이트를 커밋하지 않고 메모리에 마지막으로 커밋 된 블록 만 커밋합니다. 데이터베이스에서 단일 행을 읽거나 쓰지 않습니다. 새 블록을 같은 위치에 놓기 위해 블록을 플러시해야 할 때까지 블록을 읽거나 쓰고 메모리에 보관합니다. 메모리에있는 동안 행의 모든 ​​변경 사항이 디스크에 기록되는 것은 아니지만 "데이터베이스 기록기"프로세스가 해당 메모리 블록을 데이터 파일로 덤프하도록 신호를받을 때 블록 내용 만 기록됩니다. 따라서, 아니요 ... 응용 프로그램이 커밋되지 않은 블록을 너무 오랫동안 보유하지 않으면 문제가되지 않습니다.
Silvarion

1
문제는 임의의 DBMS가 아니라 Postgres에 관한 것입니다. 업데이트가 모두 하나씩 작성 될 필요는 없지만 데이터베이스의 모든 쓰기는 로그에 작성되어야합니다. 영구 스토리지에 변경 사항이 기록되지 않은 경우 DBMS는 어떻게 시스템 충돌에서 살아남을 수 있습니까?
ypercubeᵀᴹ

예, 검사 점 동안뿐만 아니라 메모리에서 로그에 씁니다. 동시 사용자 수가 엄청나게 많지 않으면 전혀 문제가되지 않습니다. 로그도 일괄 적으로 작성됩니다. 우리는 서버에 대해 이야기하고 있다고 생각합니다. 5400RPM HDD가 장착 된 랩톱의 Postgres 데이터베이스에 대해 이야기하는 경우 항상 성능 문제가 발생합니다. 최종 답변은 첫 번째 답변이 될 것입니다 ... 너무 많은 것들에 달려 있습니다.
Silvarion
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.