AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 278476
Accepted
Paul Draper
Paul Draper
Asked: 2020-10-22 17:41:23 +0800 CST2020-10-22 17:41:23 +0800 CST 2020-10-22 17:41:23 +0800 CST

O que é "especial" na atualização do PostgreSQL vs delete+insert

  • 772

Meu entendimento é que uma atualização bloqueia uma tupla, marca-a como excluída e adiciona uma nova tupla.

Em outras palavras, update = delete + insert.

Ou então eu tinha acreditado. Mas parece que há algo fundamentalmente diferente sobre atualização de delete + insert no MVCC.


Configurar:

CREATE TABLE example (a int PRIMARY KEY, b int);
INSERT INTO example VALUES (1, 1);

Método 1: Atualizar

-- session A                          session B
BEGIN;
UPDATE example SET b = 2 WHERE a = 1;
                                      DELETE FROM example WHERE a = 1;
COMMIT;
-- now there are 0 rows in table example (1 row was deleted by session B)

Método 2: Excluir e inserir

-- session A                          session B
BEGIN;
DELETE FROM example WHERE a = 1;
INSERT INTO example VALUES (1, 2);
                                      DELETE FROM example WHERE a = 1;
COMMIT;
-- now there is 1 row in table example (0 rows deleted by session B)

Desta forma

UPDATE example SET b = 2 WHERE a = 1;

é diferente de

DELETE FROM example WHERE a = 1;
INSERT INTO example VALUES (1, 2);

Como devo entender a natureza da atualização do MVCC? A tupla tem algum tipo de "identidade" MVCC que é preservada durante a atualização? O que é isso?

postgresql concurrency
  • 1 1 respostas
  • 2958 Views

1 respostas

  • Voted
  1. Best Answer
    Laurenz Albe
    2020-10-22T23:34:24+08:002020-10-22T23:34:24+08:00

    Sim, há uma diferença entre UPDATEe DELETE+ INSERT.

    Vamos usar a pageinspectextensão para ver as tuplas e os cabeçalhos das tuplas.

    Se você quiser repetir meu experimento, terá que descartar e recriar a tabela no meio. Além disso, pode haver sinalizadores adicionais (bits de dica) se você selecionou as linhas antes de examiná-las.

    O significado de infomask2e infomaskpode ser encontrado em src/include/access/htup_details.h, veja as citações no final da resposta.

    Após o UPDATE:

    SELECT lp, t_xmin, t_xmax, t_ctid, t_infomask2, t_infomask, t_attrs
    FROM heap_page_item_attrs(get_raw_page('example', 0), 'example');
    
     lp | t_xmin | t_xmax | t_ctid | t_infomask2 | t_infomask |            t_attrs            
    ----+--------+--------+--------+-------------+------------+-------------------------------
      1 | 380943 | 380944 | (0,2)  |       16386 |        256 | {"\\x01000000","\\x02000000"}
      2 | 380944 |      0 | (0,2)  |       32770 |      10240 | {"\\x01000000","\\x02000000"}
    (2 rows)
    
    • A primeira tupla é a morta. Seu t_ctidfoi alterado para apontar para a versão atualizada.

      Este é um dos pontos-chave, então deixe-me expandir isso: o de uma tupla ctidé a combinação do número do bloco e o “ponteiro de linha” ( lpno resultado da consulta. t_ctidapontar para a nova versão de linha. Este é o link entre a tupla original e a versão atualizada.

      t_infomask2é 2 (o número de colunas) mais HEAP_HOT_UPDATED, então esta linha recebeu uma atualização HOT (havia espaço suficiente no bloco e não há índice). t_infomaské HEAP_XMIN_COMMITTED(um pouco de dica).

    • A segunda tupla é a nova versão.

      t_infomask2é 2 plus HEAP_ONLY_TUPLE, portanto, esta é uma “tupla somente de heap” que só pode ser acessada por meio da atualização ctidda versão antiga. t_infomaské HEAP_XMAX_INVALID(true, é 0) mais HEAP_UPDATED(esta é a versão atualizada).

    Depois do DELETE+ INSERT:

    SELECT lp, t_xmin, t_xmax, t_ctid, t_infomask2, t_infomask, t_attrs
    FROM heap_page_item_attrs(get_raw_page('example', 0), 'example');
    
     lp | t_xmin | t_xmax | t_ctid | t_infomask2 | t_infomask |            t_attrs            
    ----+--------+--------+--------+-------------+------------+-------------------------------
      1 | 380958 | 380961 | (0,1)  |        8194 |        256 | {"\\x01000000","\\x02000000"}
      2 | 380961 |      0 | (0,2)  |           2 |       2048 | {"\\x01000000","\\x02000000"}
    (2 rows)
    
    • Novamente, a primeira tupla é a morta.

      t_infomask2é 2 mais HEAP_KEYS_UPDATED(esta é uma tupla excluída ou atualizada) e t_infomaské HEAP_XMIN_COMMITTED(a tupla era válida antes de ser excluída).

    • A segunda tupla é a inserida:

      t_infomask2é 2 mais, e t_infomaské HEAP_XMAX_INVALID(é 0), então esta é uma nova tupla.

    Explicação da diferença observada:

    No READ COMMITTEDnível de isolamento, uma transação sempre vê a última versão confirmada de uma linha. O DELETEna sessão B tem que bloquear a linha e é bloqueado pelo UPDATEou DELETEna sessão A.

    A documentação explica o que acontece quando o bloqueio é liberado:

    UPDATE, DELETE, SELECT FOR UPDATEe SELECT FOR SHAREcomandos se comportam da mesma forma queSELECTem termos de busca de linhas de destino: eles só encontrarão linhas de destino que foram confirmadas na hora de início do comando. No entanto, essa linha de destino pode já ter sido atualizada (ou excluída ou bloqueada) por outra transação simultânea no momento em que for encontrada. Nesse caso, o suposto atualizador aguardará que a primeira transação de atualização seja confirmada ou revertida (se ainda estiver em andamento). Se o primeiro atualizador reverter, seus efeitos serão negados e o segundo atualizador poderá prosseguir com a atualização da linha originalmente encontrada. Se o primeiro atualizador confirmar, o segundo atualizador ignorará a linha se o primeiro atualizador a excluiu, caso contrário, ele tentará aplicar sua operação à versão atualizada da linha. A condição de pesquisa do comando (oWHEREcláusula) é reavaliada para ver se a versão atualizada da linha ainda corresponde à condição de pesquisa. Em caso afirmativo, o segundo atualizador prossegue com sua operação usando a versão atualizada da linha.

    No caso de UPDATEhá um link entre a versão de linha antiga e a nova, então o PostgreSQL bloqueia e exclui a nova versão de linha, enquanto no caso de DELETE+ INSERTnão há versão válida da linha após o bloqueio ter desaparecido e nada esta deletado.

    Portanto, embora em muitos aspectos UPDATEe DELETE+ INSERTsejam bastante semelhantes no PostgreSQL, eles não são os mesmos: no segundo caso, não há conexão entre a linha excluída e a inserida.

    Apêndice: o significado de infomaskeinfomask2

    t_infomask:

    /*
     * information stored in t_infomask:
     */
    #define HEAP_HASNULL            0x0001  /* has null attribute(s) */
    #define HEAP_HASVARWIDTH        0x0002  /* has variable-width attribute(s) */
    #define HEAP_HASEXTERNAL        0x0004  /* has external stored attribute(s) */
    #define HEAP_HASOID             0x0008  /* has an object-id field */
    #define HEAP_XMAX_KEYSHR_LOCK   0x0010  /* xmax is a key-shared locker */
    #define HEAP_COMBOCID           0x0020  /* t_cid is a combo cid */
    #define HEAP_XMAX_EXCL_LOCK     0x0040  /* xmax is exclusive locker */
    #define HEAP_XMAX_LOCK_ONLY     0x0080  /* xmax, if valid, is only a locker */
    
     /* xmax is a shared locker */
    #define HEAP_XMAX_SHR_LOCK  (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)
    
    #define HEAP_LOCK_MASK  (HEAP_XMAX_SHR_LOCK | HEAP_XMAX_EXCL_LOCK | \
                             HEAP_XMAX_KEYSHR_LOCK)
    #define HEAP_XMIN_COMMITTED     0x0100  /* t_xmin committed */
    #define HEAP_XMIN_INVALID       0x0200  /* t_xmin invalid/aborted */
    #define HEAP_XMIN_FROZEN        (HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID)
    #define HEAP_XMAX_COMMITTED     0x0400  /* t_xmax committed */
    #define HEAP_XMAX_INVALID       0x0800  /* t_xmax invalid/aborted */
    #define HEAP_XMAX_IS_MULTI      0x1000  /* t_xmax is a MultiXactId */
    #define HEAP_UPDATED            0x2000  /* this is UPDATEd version of row */
    #define HEAP_MOVED_OFF          0x4000  /* moved to another place by pre-9.0
                                             * VACUUM FULL; kept for binary
                                             * upgrade support */
    #define HEAP_MOVED_IN           0x8000  /* moved from another place by pre-9.0
                                             * VACUUM FULL; kept for binary
                                             * upgrade support */
    #define HEAP_MOVED (HEAP_MOVED_OFF | HEAP_MOVED_IN)
    
    #define HEAP_XACT_MASK          0xFFF0  /* visibility-related bits */
    

    t_infomask2:

    /*
     * information stored in t_infomask2:
     */
    #define HEAP_NATTS_MASK         0x07FF  /* 11 bits for number of attributes */
    /* bits 0x1800 are available */
    #define HEAP_KEYS_UPDATED       0x2000  /* tuple was updated and key cols
                                             * modified, or tuple deleted */
    #define HEAP_HOT_UPDATED        0x4000  /* tuple was HOT-updated */
    #define HEAP_ONLY_TUPLE         0x8000  /* this is heap-only tuple */
    
    #define HEAP2_XACT_MASK         0xE000  /* visibility-related bits */
    
    • 15

relate perguntas

  • Posso ativar o PITR depois que o banco de dados foi usado

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve