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 / 108290
Accepted
Jack Douglas
Jack Douglas
Asked: 2015-07-28 23:27:52 +0800 CST2015-07-28 23:27:52 +0800 CST 2015-07-28 23:27:52 +0800 CST

Chamadas simultâneas para a mesma função: como ocorrem os deadlocks?

  • 772

Minha função new_customeré chamada várias vezes por segundo (mas apenas uma vez por sessão) por um aplicativo da web. A primeira coisa que ele faz é bloquear a customertabela (para fazer uma 'inserção se não existir' - uma variante simples de um upsert).

Meu entendimento dos documentos é que outras chamadas new_customerdevem simplesmente ficar na fila até que todas as chamadas anteriores sejam concluídas:

LOCK TABLE obtém um bloqueio em nível de tabela, aguardando, se necessário, a liberação de quaisquer bloqueios conflitantes.

Por que às vezes é um impasse em vez disso?

definição:

create function new_customer(secret bytea) returns integer language sql 
                security definer set search_path = postgres,pg_temp as $$
  lock customer in exclusive mode;
  --
  with w as ( insert into customer(customer_secret,customer_read_secret)
              select secret,decode(md5(encode(secret, 'hex')),'hex') 
              where not exists(select * from customer where customer_secret=secret)
              returning customer_id )
  insert into collection(customer_id) select customer_id from w;
  --
  select customer_id from customer where customer_secret=secret;
$$;

erro do registro:

2015-07-28 08:02:58 BST DETALHE: Processo 12380 aguarda ExclusiveLock na relação 16438 da base de dados 12141; bloqueado pelo processo 12379.
        Processo 12379 aguarda ExclusiveLock na relação 16438 do banco de dados 12141; bloqueado pelo processo 12380.
        Processo 12380: selecione new_customer(decode($1::text, 'hex'))
        Processo 12379: selecione new_customer(decode($1::text, 'hex'))
2015-07-28 08:02:58 BST DICA: Consulte o log do servidor para obter detalhes da consulta.
2015-07-28 08:02:58 BST CONTEXT: Função SQL "new_customer" instrução 1
28/07/2015 08:02:58 DECLARAÇÃO BST: selecione new_customer(decode($1::text, 'hex'))

relação:

postgres=# select relname from pg_class where oid=16438;
┌──────────┐
│ relname  │
├──────────┤
│ customer │
└──────────┘

editar:

Consegui obter um caso de teste reproduzível simples. Para mim, isso parece um bug devido a algum tipo de condição de corrida.

esquema:

create table test( id serial primary key, val text );

create function f_test(v text) returns integer language sql security definer set search_path = postgres,pg_temp as $$
  lock test in exclusive mode;
  insert into test(val) select v where not exists(select * from test where val=v);
  select id from test where val=v;
$$;

script bash executado simultaneamente em duas sessões bash:

for i in {1..1000}; do psql postgres postgres -c "select f_test('blah')"; done

log de erros (geralmente um punhado de impasses nas 1000 chamadas):

2015-07-28 16:46:19 BST ERROR:  deadlock detected
2015-07-28 16:46:19 BST DETAIL:  Process 9394 waits for ExclusiveLock on relation 65605 of database 12141; blocked by process 9393.
        Process 9393 waits for ExclusiveLock on relation 65605 of database 12141; blocked by process 9394.
        Process 9394: select f_test('blah')
        Process 9393: select f_test('blah')
2015-07-28 16:46:19 BST HINT:  See server log for query details.
2015-07-28 16:46:19 BST CONTEXT:  SQL function "f_test" statement 1
2015-07-28 16:46:19 BST STATEMENT:  select f_test('blah')

edição 2:

@ypercube sugeriu uma variante com o lado de lock tablefora da função:

for i in {1..1000}; do psql postgres postgres -c "begin; lock test in exclusive mode; select f_test('blah'); end"; done

curiosamente, isso elimina os impasses.

postgresql deadlock
  • 2 2 respostas
  • 2625 Views

2 respostas

  • Voted
  1. Best Answer
    Jack Douglas
    2015-07-29T09:56:35+08:002015-07-29T09:56:35+08:00

    Eu postei isso no pgsql-bugs e a resposta lá de Tom Lane indica que este é um problema de escalonamento de bloqueio, disfarçado pela mecânica da maneira como as funções da linguagem SQL são processadas. Essencialmente, o bloqueio gerado pelo inserté obtido antes do bloqueio exclusivo na tabela :

    Acredito que o problema com isso é que uma função SQL fará a análise (e talvez o planejamento também; não queira verificar o código agora) para todo o corpo da função de uma só vez. Isso significa que, devido ao comando INSERT, você adquire RowExclusiveLock na tabela "test" durante a análise do corpo da função, antes que o comando LOCK realmente seja executado. Portanto, o LOCK representa uma tentativa de escalonamento de bloqueio e os deadlocks são esperados.

    Essa técnica de codificação seria segura em plpgsql, mas não em uma função de linguagem SQL.

    Houve discussões sobre a reimplementação das funções da linguagem SQL para que a análise ocorra uma instrução por vez, mas não prenda a respiração sobre algo acontecendo nessa direção; não parece ser uma preocupação de alta prioridade para ninguém.

    cumprimentos, tom lane

    Isso também explica por que bloquear a tabela fora da função em um bloco plpgsql de empacotamento (conforme sugerido por @ypercube) evita os bloqueios.

    • 10
  2. alexk
    2015-07-29T06:16:13+08:002015-07-29T06:16:13+08:00

    Supondo que você execute outras instruções antes de chamar new_customer, e essas adquiram um bloqueio conflitante EXCLUSIVE(basicamente, qualquer modificação de dados na tabela customer), a explicação é muito simples.

    Pode-se reproduzir o problema com um exemplo simples (sem incluir uma função):

    CREATE TABLE test(id INTEGER);
    

    1ª sessão:

    BEGIN;
    
    INSERT INTO test VALUES(1);
    

    2ª sessão

    BEGIN;
    INSERT INTO test VALUES(1);
    LOCK TABLE test IN EXCLUSIVE MODE;
    

    1ª sessão

    LOCK TABLE test IN EXCLUSIVE MODE;
    

    Quando a primeira sessão faz a inserção, ela adquire o ROW EXCLUSIVEbloqueio em uma tabela. Enquanto isso, as tentativas da sessão 2 também obtêm o ROW EXCLUSIVEbloqueio e tentam adquirir um EXCLUSIVEbloqueio. Nesse ponto, ele deve aguardar a 1ª sessão, pois o EXCLUSIVEbloqueio entra em conflito com ROW EXCLUSIVE. Por fim, a 1ª sessão pula os tubarões e tenta conseguir uma EXCLUSIVEfechadura, mas como as fechaduras são adquiridas em ordem, entra na fila após a 2ª sessão. Este, por sua vez, aguarda o 1º, produzindo um impasse:

    DETAIL:  Process 28514 waits for ExclusiveLock on relation 58331454 of database 44697822; blocked by process 28084.
    Process 28084 waits for ExclusiveLock on relation 58331454 of database 44697822; blocked by process 28514
    

    A solução para esse problema é adquirir os bloqueios o mais cedo possível, geralmente como a primeira coisa em uma transação. Por outro lado, a carga de trabalho do PostgreSQL só precisa de bloqueios em alguns casos muito raros, então sugiro repensar a maneira como você faz o upsert (dê uma olhada neste artigo http://www.depesz.com/2012/06/10 /porque-é-insert-tão-complicado/ ).

    • 4

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