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 / 143846
Accepted
Vladimir Baranov
Vladimir Baranov
Asked: 2016-07-15 01:31:30 +0800 CST2016-07-15 01:31:30 +0800 CST 2016-07-15 01:31:30 +0800 CST

Aumente um contador para cada linha alterada

  • 772

Estou usando o SQL Server 2008 Standard, que não possui um SEQUENCErecurso.

Um sistema externo lê dados de várias tabelas dedicadas do banco de dados principal. O sistema externo mantém uma cópia dos dados e verifica periodicamente se há alterações nos dados e atualiza sua cópia.

Para tornar a sincronização eficiente, desejo transferir apenas as linhas que foram atualizadas ou inseridas desde a sincronização anterior. (As linhas nunca são excluídas). Para saber quais linhas foram atualizadas ou inseridas desde a última sincronização, há uma bigintcoluna RowUpdateCounterem cada tabela.

A ideia é que sempre que uma linha for inserida ou atualizada, o número em sua RowUpdateCountercoluna mudará. Os valores que vão para a RowUpdateCountercoluna devem ser retirados de uma sequência crescente de números. Os valores na RowUpdateCountercoluna devem ser exclusivos e cada novo valor armazenado em uma tabela deve ser maior que qualquer valor anterior.

Consulte os scripts que mostram o comportamento desejado.

Esquema

CREATE TABLE [dbo].[Test](
    [ID] [int] NOT NULL,
    [Value] [varchar](50) NOT NULL,
    [RowUpdateCounter] [bigint] NOT NULL,
CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED
(
    [ID] ASC
))
GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_RowUpdateCounter] ON [dbo].[Test]
(
    [RowUpdateCounter] ASC
)
GO

INSERIR algumas linhas

INSERT INTO [dbo].[Test]
    ([ID]
    ,[Value]
    ,[RowUpdateCounter])
VALUES
(1, 'A', ???),
(2, 'B', ???),
(3, 'C', ???),
(4, 'D', ???);

Resultado esperado

+----+-------+------------------+
| ID | Value | RowUpdateCounter |
+----+-------+------------------+
|  1 | A     |                1 |
|  2 | B     |                2 |
|  3 | C     |                3 |
|  4 | D     |                4 |
+----+-------+------------------+

Os valores gerados em RowUpdateCounterpodem ser diferentes, digamos, 5, 3, 7, 9. Eles devem ser únicos e devem ser maiores que 0, pois partimos de uma tabela vazia.

INSERT e UPDATE algumas linhas

DECLARE @NewValues TABLE (ID int NOT NULL, Value varchar(50));
INSERT INTO @NewValues (ID, Value) VALUES
(3, 'E'),
(4, 'F'),
(5, 'G'),
(6, 'H');

MERGE INTO dbo.Test WITH (HOLDLOCK) AS Dst
USING
(
    SELECT ID, Value
    FROM @NewValues
)
AS Src ON Dst.ID = Src.ID
WHEN MATCHED THEN
UPDATE SET
     Dst.Value            = Src.Value
    ,Dst.RowUpdateCounter = ???
WHEN NOT MATCHED BY TARGET THEN
INSERT
    (ID
    ,Value
    ,RowUpdateCounter)
VALUES
    (Src.ID
    ,Src.Value
    ,???)
;

Resultado esperado

+----+-------+------------------+
| ID | Value | RowUpdateCounter |
+----+-------+------------------+
|  1 | A     |                1 |
|  2 | B     |                2 |
|  3 | E     |                5 |
|  4 | F     |                6 |
|  5 | G     |                7 |
|  6 | H     |                8 |
+----+-------+------------------+
  • RowUpdateCounterpara linhas com ID 1,2devem permanecer como estão, porque essas linhas não foram alteradas.
  • RowUpdateCounterpara linhas com ID 3,4devem mudar, porque foram atualizados.
  • RowUpdateCounterpara linhas com ID 5,6devem mudar, porque foram inseridas.
  • RowUpdateCounterpara todas as linhas alteradas deve ser maior que 4 (o último RowUpdateCounterda sequência).

A ordem na qual os novos valores ( 5,6,7,8) são atribuídos às linhas alteradas realmente não importa. Os novos valores podem ter lacunas, por exemplo 15,26,47,58, mas nunca devem diminuir.

Existem várias tabelas com esses contadores no banco de dados. Não importa se todos eles usam uma única sequência global para seus números, ou se cada tabela tem sua própria sequência individual.


Não quero usar uma coluna com carimbo de data e hora em vez de um contador inteiro, porque:

  • O relógio no servidor pode avançar e retroceder. Principalmente quando está em uma máquina virtual.

  • Os valores retornados pelas funções do sistema como SYSDATETIMEsão os mesmos para todas as linhas afetadas. O processo de sincronização deve ser capaz de ler as alterações em lotes. Por exemplo, se o tamanho do lote for de 3 linhas, após a MERGEetapa acima, o processo de sincronização lerá apenas linhas E,F,G. Quando o processo de sincronização for executado na próxima vez, ele continuará da linha H.


A maneira como estou fazendo isso agora é bastante feia.

Como não há SEQUENCEno SQL Server 2008, emulo o SEQUENCEpor uma tabela dedicada com IDENTITYconforme mostrado nesta resposta . Isso em si é muito feio e exacerbado pelo fato de que preciso gerar não um único, mas um lote de números de uma vez.

Em seguida, tenho um INSTEAD OF UPDATE, INSERTgatilho em cada tabela com os RowUpdateCounterconjuntos de números necessários e gero lá.

Nas consultas INSERT, UPDATEe MERGEdefino RowUpdateCountercomo 0, que é substituído pelos valores corretos no gatilho. As ???nas consultas acima são 0.

Funciona, mas existe uma solução mais fácil?

sql-server sql-server-2008
  • 2 2 respostas
  • 2864 Views

2 respostas

  • Voted
  1. Best Answer
    Martin Smith
    2016-07-16T03:00:58+08:002016-07-16T03:00:58+08:00

    Você pode usar uma ROWVERSIONcoluna para isso.

    A documentação afirma que

    Cada banco de dados possui um contador que é incrementado para cada operação de inserção ou atualização executada em uma tabela que contém uma coluna rowversion no banco de dados.

    Os valores são BINARY(8)e você deve considerá-los como BINARYem vez de BIGINTdepois 0x7FFFFFFFFFFFFFFFque ele continua 0x80...e começa a funcionar se -9223372036854775808for tratado como assinado bigint.

    Um exemplo completo está abaixo. Manter o índice na ROWVERSIONcoluna será caro se você tiver muitas atualizações, portanto, convém testar sua carga de trabalho com e sem para ver se vale a pena o custo.

    CREATE TABLE [dbo].[Test]
      (
         [ID]               [INT] NOT NULL CONSTRAINT [PK_Test] PRIMARY KEY,
         [Value]            [VARCHAR](50) NOT NULL,
         [RowUpdateCounter] [ROWVERSION] NOT NULL UNIQUE NONCLUSTERED
      )
    
    INSERT INTO [dbo].[Test]
                ([ID],
                 [Value])
    VALUES     (1,'Foo'),
                (2,'Bar'),
                (3,'Baz');
    
    DECLARE @RowVersion_LastSynch ROWVERSION = MIN_ACTIVE_ROWVERSION();
    
    UPDATE [dbo].[Test]
    SET    [Value] = 'X'
    WHERE  [ID] = 2;
    
    DECLARE @RowVersion_ThisSynch ROWVERSION = MIN_ACTIVE_ROWVERSION();
    
    SELECT *
    FROM   [dbo].[Test]
    WHERE  [RowUpdateCounter] >= @RowVersion_LastSynch
           AND RowUpdateCounter < @RowVersion_ThisSynch;
    
    /*TODO: Store @RowVersion_ThisSynch somewhere*/
    
    DROP TABLE [dbo].[Test] 
    
    • 5
  2. Bibhuti Bhusan Padhi
    2016-07-15T03:12:06+08:002016-07-15T03:12:06+08:00

    Você já tentou usar a IDENTITYopção?

    Por exemplo:

    [RowUpdateCounter] [bigint] NOT NULL IDENTITY(1,2)
    

    Onde

    • 1 --> Valor inicial
    • 2 --> cada nova linha é incrementada por isso

    Isso é semelhante a SEQUENCE no Oracle.

    • -2

relate perguntas

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

  • Quanto "Padding" coloco em meus índices?

  • Existe um processo do tipo "práticas recomendadas" para os desenvolvedores seguirem para alterações no banco de dados?

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

  • Downgrade do SQL Server 2008 para 2005

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