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 / 223598
Accepted
GollyJer
GollyJer
Asked: 2018-11-28 16:18:46 +0800 CST2018-11-28 16:18:46 +0800 CST 2018-11-28 16:18:46 +0800 CST

Como evitar deadlocks na função de gatilho de inserção/atualização de muitos para muitos?

  • 772

Estou tendo um problema com deadlocks em uma inserção de muitos para muitos e estou muito fora do meu alcance neste momento.

Tenho uma tweettabela que recebe milhares de registros por segundo. Uma das colunas é um array[]::text[]tipo PostgreSQL com urls de zero a muitos na matriz. Parece {www.blah.com, www.blah2.com}.

O que estou tentando realizar a partir de um gatilho na tweettabela é criar uma entrada em uma urls_startingtabela e, em seguida, adicionar o relacionamento tweet/url_starting em um arquivo tweet_x_url_starting.

Observação lateral: A url_startingtabela está vinculada a uma url_endingtabela onde residem os caminhos de URL totalmente resolvidos.

O problema que enfrento são os impasses e não sei mais o que tentar.
Eu fui em uma farra de aprendizado Erwin Brandstetter . (se você está por aí cara... OBRIGADO! ?)

  1. Como implementar um relacionamento muitos-para-muitos no PostgreSQL?
  2. Deadlock com INSERTs de várias linhas apesar de ON CONFLICT NÃO FAZER NADA
  3. Postgres ATUALIZAÇÃO … LIMITE 1(skip locked help)

Eu tentei adicionar ORDER BY para ordens determinísticas e estáveis ​​e FOR UPDATE SKIP LOCKED, mas não tenho certeza se estou fazendo nada disso corretamente.

Aqui está a estrutura. Usando PostgreSQL 10.5 .

CREATE TABLE tweet(
    id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY,
    twitter_id text NOT NULL,
    created_at timestamp NOT NULL,
    content text NOT NULL,
    urls text[],
    CONSTRAINT tweet_pk PRIMARY KEY (id)
);

CREATE TABLE url_starting(
    id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY,
    url text NOT NULL,
    CONSTRAINT url_starting_pk PRIMARY KEY (id),
    CONSTRAINT url_starting_ak_1 UNIQUE (url)
);

CREATE TABLE tweet_x_url_starting(
    id_tweet integer NOT NULL,
    id_url_starting integer NOT NULL,
    CONSTRAINT tweet_x_url_starting_pk PRIMARY KEY (id_tweet,id_url_starting)

ALTER TABLE tweet_x_url_starting ADD CONSTRAINT tweet_fk FOREIGN KEY (id_tweet)
REFERENCES tweet (id) MATCH FULL
ON DELETE CASCADE ON UPDATE CASCADE;

ALTER TABLE tweet_x_url_starting ADD CONSTRAINT url_starting_fk FOREIGN KEY (id_url_starting)
REFERENCES url_starting (id) MATCH FULL
ON DELETE CASCADE ON UPDATE CASCADE;

Aqui está o tweetgatilho da tabela.

CREATE TRIGGER create_tweet_relationships
    AFTER INSERT OR UPDATE
    ON tweet
    FOR EACH ROW
    EXECUTE PROCEDURE create_tweet_relationships();

E por fim, a função.

CREATE FUNCTION create_tweet_relationships ()
    RETURNS trigger
    LANGUAGE plpgsql
    VOLATILE 
    CALLED ON NULL INPUT
    SECURITY INVOKER
    COST 1
    AS $$
BEGIN
    IF (NEW.urls IS NOT NULL) AND cardinality(NEW.urls::TEXT[]) > 0 THEN
        WITH tmp_url AS (
          INSERT INTO url_starting (url)
          SELECT UNNEST(NEW.urls)
            ORDER BY 1
          ON CONFLICT (url) DO UPDATE
            SET url = EXCLUDED.url
          RETURNING id
        )
        INSERT INTO tweet_x_url_starting (id_tweet, id_url_starting)
        SELECT NEW.id, id
            FROM tmp_url
            ORDER BY 1, 2
            FOR UPDATE SKIP LOCKED
        ON CONFLICT DO NOTHING;
    END IF;

    RETURN NULL;
END
$$;

Eu joguei cegamente as coisas que li na função sem sucesso.

O erro se parece com isso.

deadlock detected
DETAIL:  Process 11281 waits for ShareLock on transaction 1317; blocked by process 11278.
Process 11278 waits for ShareLock on transaction 1316; blocked by process 11281.
HINT:  See server log for query details.
CONTEXT:  while inserting index tuple (494,33) in relation "url_starting"
SQL statement "WITH tmp_url AS (
          INSERT INTO url_starting (url)
          SELECT UNNEST(NEW.urls)
      ORDER BY 1
          ON CONFLICT (url) DO UPDATE
              SET url = EXCLUDED.url
          RETURNING id
        )
        INSERT INTO tweet_x_url_starting (id_tweet, id_url_starting)
        SELECT NEW.id, id
            FROM tmp_url
    ORDER BY 1, 2
        FOR UPDATE SKIP LOCKED
        ON CONFLICT DO NOTHING"
PL/pgSQL function create_tweet_relationships() line 12 at SQL statement

Error causing transaction rollback (deadlocks, serialization failures, etc).

Como posso parar os impasses? Obrigado! ?

database-design postgresql
  • 2 2 respostas
  • 4394 Views

2 respostas

  • Voted
  1. Best Answer
    GollyJer
    2018-12-05T13:57:44+08:002018-12-05T13:57:44+08:00

    Isso acabou se resumindo a 2 coisas.

    1. As gravações simultâneas acabarão travando se os dados inseridos não forem classificados antes da inserção. Dentro da minha função de gatilho, todas as inserções foram classificadas, mas não havia como classificar todas as urls adicionadas simultaneamente . A única maneira de resolver esse problema era fazer backup de um nível e fazer a inserção/classificação com todo o lote de tweets, tendo assim acesso a todas as urls de uma só vez.

      Mais aqui. ? Como usar RETURNING com ON CONFLICT no PostgreSQL?

      Fazer isso fez uma grande diferença, mas não resolveu completamente o problema. ?

    2. A ON CONFLICTcláusula pode evitar erros de chave duplicada, mas não pode impedir que transações simultâneas tentem inserir as mesmas chaves .

      Mais aqui. ? Deadlock com INSERTs de várias linhas apesar de ON CONFLICT NÃO FAZER NADA

      Conforme mostrado na mensagem de erro na minha pergunta, houve conflitos no índice de tupla do sistema ctidao fazer ON CONFLICT (column) DO UPDATE. Felizmente não precisei atualizar nenhum dado, então não houve necessidade de DO UPDATEparte das minhas consultas.

      Corrigindo isso 100% parou os impasses ! ?


    Aqui ? é a consulta final enviada usando python com a execute_values()função empsycopg2 ).

    WITH cte_data (twitter_id, created_at, contents, search_hits, urls) AS (
        VALUES
        (NULL::text, NULL::timestamp, NULL::text, NULL::text[], NULL::text[]),
        %s
        OFFSET 1
    )
    , inserted_tweets AS (
        INSERT INTO tweet (twitter_id, created_at, contents, search_hits)
            SELECT twitter_id, created_at, contents, search_hits
            FROM cte_data
            ORDER BY 1
        ON CONFLICT DO NOTHING
        RETURNING id, twitter_id
        )
    , inserted_tweets_with_urls AS (
        SELECT id, urls
        FROM inserted_tweets
        JOIN cte_data USING (twitter_id)
    )
    , unique_urls AS (
        SELECT DISTINCT UNNEST(urls) url
        FROM cte_data
    )
    , new_urls AS (
        SELECT url
        FROM url_starting
        RIGHT JOIN unique_urls USING (url)
        WHERE id IS NULL
    )
    , inserted_urls AS (
        INSERT INTO url_starting (url)
            TABLE new_urls
            ORDER BY 1
        ON CONFLICT DO NOTHING
        RETURNING id, url
    )
    INSERT INTO tweet_x_url_starting (id_tweet, id_url_starting)
        SELECT it.id, iu.id
        FROM inserted_tweets_with_urls it
        JOIN inserted_urls iu
            ON (iu.url = ANY (it.urls))
        ORDER BY 1, 2
    ON CONFLICT DO NOTHING;
    
    • 3
  2. Erwin Brandstetter
    2018-11-28T20:28:09+08:002018-11-28T20:28:09+08:00

    Isso pode exigir um exame cuidadoso, conhecimento da situação completa e mais tempo do que posso gastar agora. Ou talvez eu esteja perdendo algo óbvio. Qualquer outra coisa que possa dar errado aqui, algumas coisas se destacam:

    • Remova o FOR UPDATE SKIP LOCKEDcompletamente. Não faz sentido onde você o usa. Ao selecionar no CTE, que já contém linhas com bloqueio exclusivo, isso não faz sentido. Também não faria sentido pular nenhuma linha neste estágio da consulta.

    • COST 1é enganoso. O padrão é COST 100e sua função de disparo está mais na esfera do COST 5000. Deixe o padrão ou defina-o mais alto. Provavelmente não relacionado ao impasse.

    • Um AFTERgatilho pode ser mais suscetível a deadlocks do que reescrever todo o fluxo de trabalho com uma única consulta (com vários CTEs de modificação de dados).

    • Meu tiro no escuro: o impasse é causado pela restrição FK tentando ativar um ShareLock url_startingenquanto transações simultâneas tentam modificar a mesma linha depois de terem obtido um ShareLock semelhante e vice-versa. Uma solução rápida e suja pode ser descartar a restrição FK tweet_x_url_startingse você puder pagar por isso. Você poderia pelo menos tentar isso para verificar se é parte do problema.

    Se você quiser continuar sua maratona de aprendizado - aqui está mais uma que parece relevante:

    • Como usar RETURNING com ON CONFLICT no PostgreSQL?
    • 2

relate perguntas

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

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

  • Quais são algumas maneiras de implementar um relacionamento muitos-para-muitos em um data warehouse?

  • 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