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 / user-6236

ErikE's questions

Martin Hope
ErikE
Asked: 2016-11-29 22:24:14 +0800 CST

Use o Netbackup 7.7 `WITH KEEP_CDC`

  • 3

Estou usando o SQL Server Change Data Capture em um banco de dados de produção. Para minha surpresa, descobri que, ao restaurar esse banco de dados para um ambiente inferior, os dados do CDC não são mantidos - todas as tabelas, funções e assim por diante desaparecem porque o SQL Server remove as informações do CDC durante a fase de recuperação de uma restauração para qualquer outro banco de dados além daquele que originou o backup.

Aprendi que existe uma RESTOREopção,KEEP_CDC , que pode ser usada em conjunto com a RECOVERYopção (como a última etapa de uma cadeia de restauração) para evitar que as informações do CDC sejam removidas.

REFERÊNCIA Transact-SQL: argumentos RESTORE

KEEP_CDC

Apoiado por: RESTAURAR

KEEP_CDC deve ser usado para evitar que as configurações de captura de dados alterados sejam removidas quando um backup de banco de dados ou backup de log é restaurado em outro servidor e o banco de dados é recuperado. Não é permitido especificar esta opção ao restaurar um backup com a opção NORECOVERY.

Nossa organização usa o NetBackup como principal forma de fazer backup e restaurar bancos de dados. Conseguir um arquivo de backup fora disso não é algo fácil de fazer e provavelmente nunca poderia ser rotineiro. Temos um site que permite aos desenvolvedores restaurar backups de produção em outros ambientes sem ter que mexer nos próprios arquivos.

Pergunta: Então, do que eu realmente preciso — descobrir se há uma maneira no NetBackup 7.7 de especificar opções de restauração adicionais para que WITH_CDCpossam ser passadas para o comando RESTORE? Ou o NetBackup não usa uma RESTOREdeclaração verdadeira? Parece que teria que usar de alguma forma a funcionalidade interna de restauração do SQL Server, caso contrário, não poderia acionar a fase de recuperação de uma restauração corretamente. Ou talvez eu esteja apenas fora do meu alcance, aqui.

Não consigo encontrar muitas informações sobre as habilidades do NetBackup e um engenheiro de banco de dados sênior garantiu que o NetBackup 7.7 não pode fazer isso. No entanto, estou me perguntando o quão profundamente ele pesquisou e se alguém talvez mais intimamente familiarizado com o produto possa saber uma maneira de hackear tal coisa. Aparentemente, a versão 8.0 será lançada em breve, mas novamente não consigo encontre on-line uma fonte sólida de documentação sobre como isso pode ser feito. (Parece que "argumentos de linha de comando adicionais" podem ser possíveis, mesmo que a opção não seja explicitamente suportada por meio de uma opção nomeada ou outra configuração.)

sql-server sql-server-2012
  • 2 respostas
  • 212 Views
Martin Hope
ErikE
Asked: 2016-11-19 12:03:59 +0800 CST

É seguro confiar na ordem da cláusula OUTPUT de um INSERT?

  • 25

Dada esta tabela:

CREATE TABLE dbo.Target (
   TargetId int identity(1, 1) NOT NULL,
   Color varchar(20) NOT NULL,
   Action varchar(10) NOT NULL, -- of course this should be normalized
   Code int NOT NULL,
   CONSTRAINT PK_Target PRIMARY KEY CLUSTERED (TargetId)
);

Em dois cenários ligeiramente diferentes, desejo inserir linhas e retornar os valores da coluna de identidade.

Cenário 1

INSERT dbo.Target (Color, Action, Code)
OUTPUT inserted.TargetId
SELECT t.Color, t.Action, t.Code
FROM
   (VALUES
      ('Blue', 'New', 1234),
      ('Blue', 'Cancel', 4567),
      ('Red', 'New', 5678)
   ) t (Color, Action, Code)
;

Cenário 2

CREATE TABLE #Target (
   Color varchar(20) NOT NULL,
   Action varchar(10) NOT NULL,
   Code int NOT NULL,
   PRIMARY KEY CLUSTERED (Color, Action)
);

-- Bulk insert to the table the same three rows as above by any means

INSERT dbo.Target (Color, Action, Code)
OUTPUT inserted.TargetId
SELECT t.Color, t.Action, t.Code
FROM #Target
;

Pergunta

Posso confiar que os valores de identidade retornados da dbo.Targetinserção da tabela serão retornados na ordem em que existiam na VALUEScláusula 1) e na #Targettabela 2), para que eu possa correlacioná-los por sua posição no conjunto de linhas de saída de volta à entrada original?

Para referência

Aqui está um código C# reduzido que demonstra o que está acontecendo no aplicativo (cenário 1, que será convertido em breve para usar SqlBulkCopy):

public IReadOnlyCollection<Target> InsertTargets(IEnumerable<Target> targets) {
   var targetList = targets.ToList();
   const string insertSql = @"
      INSERT dbo.Target (
         CoreItemId,
         TargetDateTimeUtc,
         TargetTypeId,
      )
      OUTPUT
         Inserted.TargetId
      SELECT
         input.CoreItemId,
         input.TargetDateTimeUtc,
         input.TargetTypeId,
      FROM
         (VALUES
            {0}
         ) input (
            CoreItemId,
            TargetDateTimeUtc,
            TargetTypeId
         );";
   var results = Connection.Query<DbTargetInsertResult>(
      string.Format(
         insertSql,
         string.Join(
            ", ",
            targetList
               .Select(target => $@"({target.CoreItemId
                  }, '{target.TargetDateTimeUtc:yyyy-MM-ddTHH:mm:ss.fff
                  }', {(byte) target.TargetType
                  })";
               )
         )
      )
      .ToList();
   return targetList
      .Zip( // The correlation that relies on the order of the two inputs being the same
         results,
         (inputTarget, insertResult) => new Target(
            insertResult.TargetId, // with the new TargetId to replace null.
            inputTarget.TargetDateTimeUtc,
            inputTarget.CoreItemId,
            inputTarget.TargetType
         )
      )
      .ToList()
      .AsReadOnly();
}
sql-server sql-server-2012
  • 1 respostas
  • 3902 Views
Martin Hope
ErikE
Asked: 2016-11-18 14:39:48 +0800 CST

Fonte autoritativa que <> e != são idênticas em desempenho no SQL Server

  • 89

Considere esta resposta no SO que tranquiliza o questionador sobre o <>operador que:

<>é ... o mesmo que !=.

Mas então um comentarista se intromete e diz:

É verdade que eles são, funcionalmente, os mesmos. No entanto, como o otimizador SQL os usa é muito diferente. =/!= são simplesmente avaliados como verdadeiro/falso, enquanto <> significa que o mecanismo precisa verificar se o valor é maior ou menor, o que significa mais sobrecarga de desempenho. Apenas algo a considerar ao escrever consultas que podem ser caras.

Estou confiante de que isso é falso, mas, para abordar os céticos em potencial, me pergunto se alguém pode fornecer uma fonte autorizada ou canônica para provar que esses operadores não são apenas funcionalmente iguais, mas idênticos em todos os aspectos.

sql-server performance
  • 4 respostas
  • 17469 Views
Martin Hope
ErikE
Asked: 2013-05-29 10:03:10 +0800 CST

sp_executesql adiciona instruções ao script dinâmico executado?

  • 4

A Pergunta :

Tanto quanto eu posso dizer, sp_executesqladiciona instruções ao início do script SQL dinâmico enviado. Porém, um rastreamento do SQL Profiler não captura as instruções extras e nem o DBCC OUTPUTBUFFER. Então:

  1. Existe alguma maneira de ver as instruções extras adicionadas aos lotes SQL dinâmicos enviados por sp_executesql?
  2. Alguém pode confirmar definitivamente que minhas conclusões sobre as declarações extras estão corretas/incorretas?

Fundo

Eu tenho um banco de dados onde alguns objetos (views, sinônimos, SPs) são reescritos com base nos dados de uma Scripttabela. Se o banco de dados for movido para outro servidor, um procedimento armazenado percorre as linhas da Scripttabela, substitui certos valores de chave no script SQL fornecido por aqueles definidos para o novo contexto do servidor e executa o script.

Tudo estava funcionando bem até que fiz alguns ajustes para adicionar suporte para permissões de script por meio desse mesmo mecanismo. O banco de dados integra-se ao produto de um fornecedor e, em cada ambiente, o banco de dados do fornecedor pode ter um usuário diferente que deve receber permissão para uma exibição específica em meu banco de dados para fins de relatório. Portanto, tenho que consultar esse usuário (no banco de dados do fornecedor), usar esse nome para criar o usuário em meu banco de dados, se ele não existir e, finalmente, conceder SELECTpermissão. Isso exigia scripts mais demorados e fazer dynamic-sql dentro do dynamic-sql, então eu queria passar o @Debugparâmetro do meu script externo para poder ver o script extra que estava sendo gerado e confirmar sua correção antes de tentar executá-lo.

Além de alterar quais tipos de objeto podem ser incluídos no script e tornar o DROPscript opcional, a única alteração material que fiz para acomodar o @Debugparâmetro foi alterar isto:

EXEC (@CreateSQL);

para isso:

EXEC sp_executesql @CreateSQL, N'@Debug bit', @Debug;

Então me deparei com um problema: o único procedimento armazenado em minha Scripttabela não podia mais ser criado, embora o DROPanterior ainda funcionasse bem. O resultado que obtive foi este:

Msg 156, Nível 15, Estado 1, Linha 1

Sintaxe incorreta perto da palavra-chave 'PROCEDIMENTO'.

Isso foi muito confuso, mas depois de discutir com ele por algum tempo, finalmente descobri o problema: sp_executesqlvincula parâmetros ao SQL dinâmico adicionando secretamente uma DECLAREinstrução ao topo antes de executar. Como CREATE PROCEDUREdeve ser a única instrução no lote, mas agora há uma instrução extra antes da CREATE PROCEDURElinha, ela gera um erro. Ele diz Line 1- o que me enganou ainda mais - mas isso é obviamente ajustado pelo mecanismo para que as pessoas não fiquem confusas sobre os números de linha de seu próprio script ao lidar com erros.

A solução para o problema foi detectar com qual tipo de objeto estava sendo trabalhado e NÃO passar o @Debugparâmetro para que o script que não deve ter outras instruções funcione bem. Uma mudança rápida fez o trabalho:

IF @ScriptType IN ('Procedure', 'View', 'Function') BEGIN
   EXEC sp_executesql @CreateSQL;
END
ELSE BEGIN
   EXEC sp_executesql @CreateSQL, N'@Debug bit', @Debug;
END;

Eu também poderia ter aninhado meu SQL dinâmico um nível mais profundo, para criar o procedimento dentro do SQL dinâmico (novamente, dentro do script na tabela), mas essa foi uma solução menos ideal no meu caso.

Suspeito que o uso OUTPUTde variáveis ​​com sp_executesqltambém adicionaria uma ou mais instruções ao final do script para permitir que o mecanismo as capture, provavelmente em uma SELECTinstrução que é silenciosamente engolida.

sql-server dynamic-sql
  • 2 respostas
  • 3256 Views
Martin Hope
ErikE
Asked: 2012-08-17 16:32:19 +0800 CST

Por que "Lookup" é colorido como uma palavra reservada de função no SQL Server?

  • 14

No SSMS 2208, o identificador "Lookup" é colorido de rosa choque como se fosse uma função (mesma cor de, digamos, "Power" ou "Convert"). Por quê?

Não consigo encontrá-lo na lista oficial de palavras reservadas . As pesquisas na web parecem inúteis, pois há muitos termos de "pesquisa" por aí que não têm nada a ver com a minha pergunta.

sql-server-2008 ssms
  • 1 respostas
  • 1875 Views
Martin Hope
ErikE
Asked: 2012-07-05 14:09:38 +0800 CST

Tabela de fila FIFO para vários trabalhadores no SQL Server

  • 18

Eu estava tentando responder à seguinte pergunta do stackoverflow:

  • Qual abordagem de bloqueio do SQL Server 2005/2008 devo usar para processar linhas de tabelas individuais em várias instâncias de aplicativos de servidor?

Depois de postar uma resposta um tanto ingênua, pensei em colocar meu dinheiro onde estava minha boca e realmente testar o cenário que estava sugerindo, para ter certeza de que não estava mandando o OP em uma caça ao ganso selvagem. Bem, acabou sendo muito mais difícil do que eu pensava (não é surpresa para ninguém, tenho certeza).

Aqui está o que eu tentei e pensei:

  • Primeiro tentei um TOP 1 UPDATE com um ORDER BY dentro de uma tabela derivada, usando ROWLOCK, READPAST. Isso gerou impasses e também processou itens fora de ordem. Deve ser o mais próximo possível do FIFO, exceto erros que exijam a tentativa de processar a mesma linha mais de uma vez.

  • Em seguida, tentei selecionar o próximo QueueID desejado em uma variável, usando várias combinações de READPAST, UPDLOCK, HOLDLOCKe ROWLOCKpara preservar exclusivamente a linha para atualização por essa sessão. Todas as variações que experimentei sofriam dos mesmos problemas de antes, bem como, para certas combinações com READPAST, reclamando:

    Você só pode especificar o bloqueio READPAST nos níveis de isolamento READ COMMITTED ou REPEATABLE READ.

    Isso foi confuso porque foi READ COMMITTED. Já passei por isso antes e é frustrante.

  • Desde que comecei a escrever esta pergunta, Remus Rusani postou uma nova resposta para a pergunta. Eu li seu artigo vinculado e vejo que ele está usando leituras destrutivas, já que ele disse em sua resposta que "não é realisticamente possível manter os bloqueios durante as chamadas da web". Depois de ler o que seu artigo diz sobre pontos de acesso e páginas que exigem bloqueio para fazer qualquer atualização ou exclusão, temo que, mesmo que eu fosse capaz de descobrir os bloqueios corretos para fazer o que estou procurando, não seria escalável e poderia não lidar com simultaneidade massiva.

Agora eu não tenho certeza para onde ir. É verdade que manter bloqueios enquanto a linha é processada não pode ser alcançado (mesmo que não suporte tps altos ou simultaneidade massiva)? o que estou perdendo?

Na esperança de que pessoas mais inteligentes do que eu e pessoas mais experientes do que eu possam ajudar, abaixo está o script de teste que eu estava usando. Ele voltou para o método TOP 1 UPDATE, mas deixei o outro método, comentado, caso você queira explorar isso também.

Cole cada um deles em uma sessão separada, execute a sessão 1 e, em seguida, rapidamente todas as outras. Em cerca de 50 segundos, o teste terminará. Veja as mensagens de cada sessão para ver o trabalho que ela fez (ou como falhou). A primeira sessão mostrará um conjunto de linhas com um instantâneo obtido uma vez por segundo, detalhando os bloqueios presentes e os itens da fila sendo processados. Às vezes funciona e outras vezes não funciona de jeito nenhum.

Sessão 1

/* Session 1: Setup and control - Run this session first, then immediately run all other sessions */
IF Object_ID('dbo.Queue', 'U') IS NULL
   CREATE TABLE dbo.Queue (
      QueueID int identity(1,1) NOT NULL,
      StatusID int NOT NULL,
      QueuedDate datetime CONSTRAINT DF_Queue_QueuedDate DEFAULT (GetDate()),
      CONSTRAINT PK_Queue PRIMARY KEY CLUSTERED (QueuedDate, QueueID)
   );

IF Object_ID('dbo.QueueHistory', 'U') IS NULL
   CREATE TABLE dbo.QueueHistory (
      HistoryDate datetime NOT NULL,
      QueueID int NOT NULL
   );

IF Object_ID('dbo.LockHistory', 'U') IS NULL
   CREATE TABLE dbo.LockHistory (
      HistoryDate datetime NOT NULL,
      ResourceType varchar(100),
      RequestMode varchar(100),
      RequestStatus varchar(100),
      ResourceDescription varchar(200),
      ResourceAssociatedEntityID varchar(200)
   );

IF Object_ID('dbo.StartTime', 'U') IS NULL
   CREATE TABLE dbo.StartTime (
      StartTime datetime NOT NULL
   );

SET NOCOUNT ON;

IF (SELECT Count(*) FROM dbo.Queue) < 10000 BEGIN
   TRUNCATE TABLE dbo.Queue;

   WITH A (N) AS (SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
   B (N) AS (SELECT 1 FROM A Z, A I, A P),
   C (N) AS (SELECT Row_Number() OVER (ORDER BY (SELECT 1)) FROM B O, B W)
   INSERT dbo.Queue (StatusID, QueuedDate)
   SELECT 1, DateAdd(millisecond, C.N * 3, GetDate() - '00:05:00')
   FROM C
   WHERE C.N <= 10000;
END;

TRUNCATE TABLE dbo.StartTime;
INSERT dbo.StartTime SELECT GetDate() + '00:00:15'; -- or however long it takes you to go run the other sessions
GO
TRUNCATE TABLE dbo.QueueHistory;
SET NOCOUNT ON;

DECLARE
   @Time varchar(8),
   @Now datetime;
SELECT @Time = Convert(varchar(8), StartTime, 114)
FROM dbo.StartTime;
WAITFOR TIME @Time;

DECLARE @i int,
@QueueID int;
SET @i = 1;
WHILE @i <= 33 BEGIN
   SET @Now  = GetDate();
   INSERT dbo.QueueHistory
   SELECT
      @Now,
      QueueID
   FROM
      dbo.Queue Q WITH (NOLOCK)
   WHERE
      Q.StatusID <> 1;

   INSERT dbo.LockHistory
   SELECT
      @Now,
      L.resource_type,
      L.request_mode,
      L.request_status,
      L.resource_description,
      L.resource_associated_entity_id
   FROM
      sys.dm_tran_current_transaction T
      INNER JOIN sys.dm_tran_locks L
         ON L.request_owner_id = T.transaction_id;
   WAITFOR DELAY '00:00:01';
   SET @i = @i + 1;
END;

WITH Cols AS (
   SELECT *, Row_Number() OVER (PARTITION BY HistoryDate ORDER BY QueueID) Col
   FROM dbo.QueueHistory
), P AS (
   SELECT *
   FROM
      Cols
      PIVOT (Max(QueueID) FOR Col IN ([1], [2], [3], [4], [5], [6], [7], [8])) P
)
SELECT L.*, P.[1], P.[2], P.[3], P.[4], P.[5], P.[6], P.[7], P.[8]
FROM
   dbo.LockHistory L
   FULL JOIN P
      ON L.HistoryDate = P.HistoryDate

/* Clean up afterward
DROP TABLE dbo.StartTime;
DROP TABLE dbo.LockHistory;
DROP TABLE dbo.QueueHistory;
DROP TABLE dbo.Queue;
*/

Sessão 2

/* Session 2: Simulate an application instance holding a row locked for a long period, and eventually abandoning it. */
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET NOCOUNT ON;
SET XACT_ABORT ON;

DECLARE
   @QueueID int,
   @Time varchar(8);
SELECT @Time = Convert(varchar(8), StartTime + '0:00:01', 114)
FROM dbo.StartTime;
WAITFOR TIME @Time;
BEGIN TRAN;

--SET @QueueID = (
--   SELECT TOP 1 QueueID
--   FROM dbo.Queue WITH (READPAST, UPDLOCK)
--   WHERE StatusID = 1 -- ready
--   ORDER BY QueuedDate, QueueID
--);

--UPDATE dbo.Queue
--SET StatusID = 2 -- in process
----OUTPUT Inserted.*
--WHERE QueueID = @QueueID;

SET @QueueID = NULL;
UPDATE Q
SET Q.StatusID = 1, @QueueID = Q.QueueID
FROM (
   SELECT TOP 1 *
   FROM dbo.Queue WITH (ROWLOCK, READPAST)
   WHERE StatusID = 1
   ORDER BY QueuedDate, QueueID
) Q

PRINT @QueueID;

WAITFOR DELAY '00:00:20'; -- Release it partway through the test

ROLLBACK TRAN; -- Simulate client disconnecting

Sessão 3

/* Session 3: Run a near-continuous series of "failed" queue processing. */
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET XACT_ABORT ON;
SET NOCOUNT ON;
DECLARE
   @QueueID int,
   @EndDate datetime,
   @NextDate datetime,
   @Time varchar(8);

SELECT
   @EndDate = StartTime + '0:00:33',
   @Time = Convert(varchar(8), StartTime, 114)
FROM dbo.StartTime;

WAITFOR TIME @Time;

WHILE GetDate() < @EndDate BEGIN
   BEGIN TRAN;

   --SET @QueueID = (
   --   SELECT TOP 1 QueueID
   --   FROM dbo.Queue WITH (READPAST, UPDLOCK)
   --   WHERE StatusID = 1 -- ready
   --   ORDER BY QueuedDate, QueueID
   --);

   --UPDATE dbo.Queue
   --SET StatusID = 2 -- in process
   ----OUTPUT Inserted.*
   --WHERE QueueID = @QueueID;

   SET @QueueID = NULL;
   UPDATE Q
   SET Q.StatusID = 1, @QueueID = Q.QueueID
   FROM (
      SELECT TOP 1 *
      FROM dbo.Queue WITH (ROWLOCK, READPAST)
      WHERE StatusID = 1
      ORDER BY QueuedDate, QueueID
   ) Q

   PRINT @QueueID;

   SET @NextDate = GetDate() + '00:00:00.015';
   WHILE GetDate() < @NextDate SET NOCOUNT ON;
   ROLLBACK TRAN;
END

Sessão 4 e superior -- quantas quiser

/* Session 4: "Process" the queue normally, one every second for 30 seconds. */
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET XACT_ABORT ON;
SET NOCOUNT ON;

DECLARE @Time varchar(8);
SELECT @Time = Convert(varchar(8), StartTime, 114)
FROM dbo.StartTime;
WAITFOR TIME @Time;

DECLARE @i int,
@QueueID int;
SET @i = 1;
WHILE @i <= 30 BEGIN
   BEGIN TRAN;

   --SET @QueueID = (
   --   SELECT TOP 1 QueueID
   --   FROM dbo.Queue WITH (READPAST, UPDLOCK)
   --   WHERE StatusID = 1 -- ready
   --   ORDER BY QueuedDate, QueueID
   --);

   --UPDATE dbo.Queue
   --SET StatusID = 2 -- in process
   --WHERE QueueID = @QueueID;

   SET @QueueID = NULL;
   UPDATE Q
   SET Q.StatusID = 1, @QueueID = Q.QueueID
   FROM (
      SELECT TOP 1 *
      FROM dbo.Queue WITH (ROWLOCK, READPAST)
      WHERE StatusID = 1
      ORDER BY QueuedDate, QueueID
   ) Q

   PRINT @QueueID;
   WAITFOR DELAY '00:00:01'
   SET @i = @i + 1;
   DELETE dbo.Queue
   WHERE QueueID = @QueueID;   
   COMMIT TRAN;
END
sql-server locking
  • 2 respostas
  • 20980 Views
Martin Hope
ErikE
Asked: 2012-02-14 10:43:22 +0800 CST

Recursos para entender o bloqueio e a simultaneidade do SQL Server?

  • 9

Como demonstrado por uma questão recente de bloqueio de minas e simultaneidade são difíceis.

Você pode sugerir algum bom recurso para profissionais de SQL intermediários a avançados fazerem um estudo aprofundado sobre eles que, devidamente aprendidos, permitiriam uma melhor navegação de todas as armadilhas inerentes a essa área?

Estou pensando em todos os tipos de recursos - tutoriais, blogs, páginas de manual, sessões PASS ou qualquer coisa.

sql-server locking
  • 4 respostas
  • 758 Views
Martin Hope
ErikE
Asked: 2012-02-12 17:06:23 +0800 CST

Gerenciando simultaneidade ao usar o padrão SELECT-UPDATE

  • 26

Digamos que você tenha o seguinte código (ignore que é horrível):

BEGIN TRAN;
DECLARE @id int
SELECT @id = id + 1 FROM TableA;
UPDATE TableA SET id = @id; --TableA must have only one row, apparently!
COMMIT TRAN;
-- @id is returned to the client or used somewhere else

A meu ver, isso NÃO está gerenciando a simultaneidade corretamente. Só porque você tem uma transação não significa que outra pessoa não lerá o mesmo valor que você leu antes de chegar ao seu extrato de atualização.

Agora, deixando o código como está (percebo que isso é melhor tratado como uma única instrução ou ainda melhor usando uma coluna de autoincremento/identidade), quais são as maneiras seguras de fazê-lo lidar com a simultaneidade adequadamente e evitar condições de corrida que permitem que dois clientes obtenham o mesmo valor id?

Tenho certeza de que adicionar um WITH (UPDLOCK, HOLDLOCK)ao SELECT resolverá o problema. O nível de isolamento da transação SERIALIZABLE também parece funcionar, pois nega que qualquer outra pessoa leia o que você fez até que a transferência termine ( ATUALIZAÇÃO : isso é falso. Veja a resposta de Martin). Isso é verdade? Ambos funcionarão igualmente bem? Um é preferido em detrimento do outro?

Imagine fazer algo mais legítimo do que uma atualização de ID - algum cálculo baseado em uma leitura que você precisa atualizar. Pode haver muitas tabelas envolvidas, algumas das quais você escreverá e outras não. Qual é a melhor prática aqui?

Tendo escrito esta pergunta, acho que as dicas de bloqueio são melhores porque você está apenas bloqueando as tabelas de que precisa, mas gostaria da opinião de qualquer pessoa.

PS E não, não sei a melhor resposta e realmente quero entender melhor! :)

sql-server locking
  • 3 respostas
  • 14956 Views
Martin Hope
ErikE
Asked: 2012-02-10 11:51:19 +0800 CST

Mostre facilmente linhas diferentes entre duas tabelas ou consultas

  • 20

Imagine que você tenha duas tabelas/consultas diferentes que deveriam ter/retornar dados idênticos. Você deseja verificar isso. Qual é uma maneira fácil de mostrar todas as linhas não correspondentes de cada tabela, como no exemplo abaixo, comparando todas as colunas? Suponha que haja 30 colunas nas tabelas, muitas das quais são NULLable.

Quando não há PK ou pode haver duplicatas por PK, juntar apenas colunas PK não é suficiente, e seria um desastre ter que fazer um FULL JOIN com 30 condições de junção que lidam adequadamente com NULLs, além de uma desagradável condição WHERE para excluir as linhas correspondentes.

Normalmente, é quando estou escrevendo uma nova consulta contra dados não apagados ou não totalmente compreendidos que o problema é pior e a probabilidade de um PK estar logicamente disponível é extremamente baixa. Eu crio duas maneiras diferentes de resolver o problema e depois comparo seus resultados, as diferenças destacando casos especiais nos dados que eu desconhecia.

O resultado precisa ficar assim:

Which   Col1   Col2   Col3   ... Col30
------  ------ ------ ------     ------
TableA  Cat    27     86               -- mismatch
TableB  Cat    27     105              -- mismatch
TableB  Cat    27     87               -- mismatch 2
TableA  Cat    128    92               -- no corresponding row
TableB  Lizard 83     NULL             -- no corresponding row

Se [Col1, Col2]acontecer de ser uma chave composta e ordenarmos por elas em nosso resultado final, podemos ver facilmente que A e B têm uma linha diferente que deve ser a mesma, e cada uma tem uma linha que não está na outra.

No exemplo acima, não é desejável ver a primeira linha duas vezes.

Aqui está DDL e DML para configurar tabelas e dados de amostra:

CREATE TABLE dbo.TableA (
   Col1 varchar(10),
   Col2 int,
   Col3 int,
   Col4 varchar(10),
   Col5 varchar(10),
   Col6 varchar(10),
   Col7 varchar(10),
   Col8 varchar(10),
   Col9 varchar(10),
   Col10 varchar(10),
   Col11 varchar(10),
   Col12 varchar(10),
   Col13 varchar(10),
   Col14 varchar(10),
   Col15 varchar(10),
   Col16 varchar(10),
   Col17 varchar(10),
   Col18 varchar(10),
   Col19 varchar(10),
   Col20 varchar(10),
   Col21 varchar(10),
   Col22 varchar(10),
   Col23 varchar(10),
   Col24 varchar(10),
   Col25 varchar(10),
   Col26 varchar(10),
   Col27 varchar(10),
   Col28 varchar(10),
   Col29 varchar(10),
   Col30 varchar(10)
);

CREATE TABLE dbo.TableB (
   Col1 varchar(10),
   Col2 int,
   Col3 int,
   Col4 varchar(10),
   Col5 varchar(10),
   Col6 varchar(10),
   Col7 varchar(10),
   Col8 varchar(10),
   Col9 varchar(10),
   Col10 varchar(10),
   Col11 varchar(10),
   Col12 varchar(10),
   Col13 varchar(10),
   Col14 varchar(10),
   Col15 varchar(10),
   Col16 varchar(10),
   Col17 varchar(10),
   Col18 varchar(10),
   Col19 varchar(10),
   Col20 varchar(10),
   Col21 varchar(10),
   Col22 varchar(10),
   Col23 varchar(10),
   Col24 varchar(10),
   Col25 varchar(10),
   Col26 varchar(10),
   Col27 varchar(10),
   Col28 varchar(10),
   Col29 varchar(10),
   Col30 varchar(10)
);

INSERT dbo.TableA (Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9, Col10, Col11, Col12, Col13, Col14, Col15, Col16, Col17, Col18, Col19, Col20, Col21, Col22, Col23, Col24, Col25, Col26, Col27, Col28, Col29, Col30)
VALUES
   ('Cat', 27, 86, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
   ('Cat', 128, 92, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
   ('Porcupine', NULL, 42, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
   ('Tapir', NULL, NULL, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0')
;

INSERT dbo.TableB (Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9, Col10, Col11, Col12, Col13, Col14, Col15, Col16, Col17, Col18, Col19, Col20, Col21, Col22, Col23, Col24, Col25, Col26, Col27, Col28, Col29, Col30)
VALUES
   ('Cat', 27, 105, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
   ('Cat', 27, 87, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
   ('Lizard', 83, NULL, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
   ('Porcupine', NULL, 42, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
   ('Tapir', NULL, NULL, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0');
sql-server sql-server-2008
  • 4 respostas
  • 112502 Views

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