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 / 117187
Accepted
Vaccano
Vaccano
Asked: 2015-10-07 09:56:45 +0800 CST2015-10-07 09:56:45 +0800 CST 2015-10-07 09:56:45 +0800 CST

Usando RowLock para impor uma vez e somente uma vez

  • 772

Eu tenho um serviço da Web que pode disparar uma cadeia de eventos para um pedido. Ele faz isso quando recebe uma mensagem informando (máximo de cerca de 2 por segundo).

O problema que tenho é que tenho mais de uma instância do Web Service e, às vezes, diferentes partes do pedido podem atingir cada instância exatamente ao mesmo tempo. Isso faz com que a cadeia de eventos seja disparada mais de uma vez para a ordem (ruim).

Então, eu estava pensando, eu poderia fazer uma tabela que é apenas o ID do pedido e um sinalizador dizendo se a "cadeia de eventos" já foi disparada.

Eu poderia então iniciar uma transação no meu código. Algo assim:

mySqlConnection.BeginTransaction(); // C# Code

Eu poderia selecionar a linha para o pedido em questão assim:

SET TRANSACTION ISOLATION LEVEL READ COMMITTED

SELECT  OrderId, IsChainFired
FROM    OrderedChainFlag WITH ( ROWLOCK, XLOCK, HOLDLOCK )
WHERE   OrderId = 123456

Então, se IsChainFired for falso, dispara a "Cadeia de Eventos". Eu então executaria:

UPDATE  OrderedChainFlag 
SET     IsChainFired = 1
WHERE   OrderId = 123456

e execute (mesmo que IsChainFired seja verdadeiro):

myConnection.CommitTransaction(); // C# Code

Isso impediria que mais de uma instância do serviço lesse que a cadeia está livre para ser executada ao mesmo tempo.

Minha preocupação (e minha pergunta) é escalonamento de bloqueio . Se isso permanecer em bloqueios de linha, será uma solução fantástica para o meu problema. Mas se os bloqueios aumentarem para página ou tabela, terei acabado de criar um gargalo em meu sistema.

Então, há algo que eu possa fazer para garantir que isso permaneça no nível de bloqueio de linha? (ou é mesmo uma boa ideia usar o sistema de bloqueio de banco de dados como um semáforo como este?)

NOTA: OrderId seria a chave primária, o índice clusterizado e o índice de particionamento da tabela.

sql-server sql-server-2012
  • 1 1 respostas
  • 274 Views

1 respostas

  • Voted
  1. Best Answer
    Hannah Vernon
    2015-10-07T10:05:44+08:002015-10-07T10:05:44+08:00

    Você pode usar a OUTPUTcláusula para ver se a cadeia de eventos deve ser "disparada":

    Minha cama de teste:

    CREATE TABLE dbo.OrderedChainFlag
    (
        IsChainFired BIT NOT NULL
            CONSTRAINT DF_OrderedChainFlag_IsChainFired
            DEFAULT ((0))
        , OrderID INT NOT NULL
    );
    
    CREATE INDEX IX_OrderedChainFlag_Firing
    ON dbo.OrderedChainFlag(OrderID, IsChainFired);
    
    GO
    
    INSERT INTO dbo.OrderedChainFlag (OrderID)
    VALUES (123456);
    

    Execute isto para ver a saída:

    UPDATE OrderedChainFlag 
    SET IsChainFired = 1 
    OUTPUT inserted.IsChainFired, inserted.OrderID
    WHERE OrderId = 123456 
        and IsChainFired = 0;
    

    Use a DataReaderpara ler os resultados da UPDATEinstrução; se uma linha for retornada por .Read()você sabe que a tabela foi atualizada e, efetivamente, você pode executar a cadeia de eventos.

    A execução da UPDATEinstrução acima só fornecerá saída se ela realmente atualizar a IsChainFiredcoluna para 1. Você pode provar isso executando a instrução de atualização duas vezes. O primeiro mostra a saída, o segundo não.

    Como essa instrução é atômica, uma atualização única será bem-sucedida, sem afetar o escalonamento de bloqueio, supondo que você tenha um bom índice em OrderIde IsChainFired, e esse índice esteja configurado WITH (ALLOW_ROW_LOCKS = ON).


    A segunda opção, que é uma pequena variação da anterior, seria não especificar o próximo OrderIDa ser processado; em vez disso, basta selecionar o próximo que tem IsChainFired = 0:

    CREATE INDEX IX_OrderedChainFlag_IsFired
    ON dbo.OrderedChainFlag(IsChainFired);
    
    UPDATE TOP(1) OrderedChainFlag 
    SET IsChainFired = 1 
    OUTPUT inserted.IsChainFired, inserted.OrderID
    WHERE IsChainFired = 0;
    

    A UPDATEinstrução, neste caso, retorna OrderIDpara uma única linha diretamente do IX_OrderedChainFlag_IsFiredíndice.

    Eu inseri mais de 750.000 linhas na tabela OrderedChainFlag em meu ambiente de teste e executei a UPDATE TOP(1)instrução acima, com o índice que mencionei no lugar, e obtive o seguinte plano:

    insira a descrição da imagem aqui

    Um bônus (discutível) aqui é que você poderia retornar mais do que TOP(1)linhas para processamento, talvez usando vários encadeamentos em seu serviço da Web.

    Você provavelmente também deve ler esta pergunta , juntamente com as excelentes respostas sobre simultaneidade.

    • 2

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

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