Respostas:
Para o SQL Server, você poderia argumentar que uma operação de confirmação nada mais é do que gravar LOP_COMMIT_XACT no arquivo de log e liberar bloqueios, o que obviamente será mais rápido que o ROLLBACK de todas as ações que sua transação executou desde BEGIN TRAN.
Se você está considerando todas as ações de uma transação, não apenas o commit, eu ainda argumentaria que sua afirmação não é verdadeira. Excluindo fatores externos, a velocidade do disco de log em comparação com a velocidade do disco de dados, por exemplo, é provável que a reversão de qualquer trabalho realizado por uma transação seja mais rápida do que fazer o trabalho em primeiro lugar.
Uma reversão está lendo um arquivo seqüencial de alterações e aplicando-as às páginas de dados na memória. O "trabalho" original tinha que gerar um plano de execução, adquirir páginas, juntar linhas etc.
Edit: O depende pouco ...
O @JackDouglas apontou para este artigo, que descreve uma das situações em que a reversão pode demorar significativamente mais que a operação original. O exemplo é uma transação de 14 horas, inevitavelmente usando paralelismo, que leva mais de 48 horas para retroceder porque o retrocesso é principalmente de thread único. Você provavelmente também estaria agitando o buffer pool repetidamente, para não mais reverter as alterações nas páginas na memória.
Portanto, uma versão revisada da minha resposta anterior. Quanto mais lenta é a reversão? Todas as outras coisas consideradas, para uma transação OLTP típica, não é. Fora dos limites do típico, pode levar mais tempo para "desfazer" do que "fazer", mas (isso é um trava-língua em potencial?) Por que dependerá de como o "fazer" foi feito.
Edit2: Seguindo a discussão nos comentários, aqui está um exemplo muito elaborado para demonstrar que o trabalho que está sendo feito é o principal fator na determinação da despesa relativa de consolidação versus reversão como operações.
Crie duas tabelas e embale-as ineficientemente (espaço desperdiçado por página):
SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;
SET NOCOUNT ON;
GO
CREATE TABLE dbo.Foo
(
col1 INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
, col2 CHAR(4000) NOT NULL DEFAULT REPLICATE('A', 4000)
)
CREATE TABLE dbo.Bar
(
col1 INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
, col2 CHAR(4000) NOT NULL DEFAULT REPLICATE('A', 4000)
)
GO
INSERT dbo.Foo DEFAULT VALUES
GO 100000
INSERT dbo.Bar DEFAULT VALUES
GO 100000
Execute uma consulta de atualização "ruim", medindo o tempo necessário para realizar o trabalho e o tempo necessário para emitir a confirmação.
DECLARE
@StartTime DATETIME2
, @Rows INT
SET @Rows = 1
CHECKPOINT
DBCC DROPCLEANBUFFERS
BEGIN TRANSACTION
SET @StartTime = SYSDATETIME()
UPDATE
dbo.bar
SET
col2 = REPLICATE('B', 4000)
FROM
dbo.bar b
INNER JOIN
(
SELECT TOP(@Rows)
col1
FROM
dbo.foo
ORDER BY
NEWID()
) f
ON f.col1 = b.col1
OPTION (MAXDOP 1)
SELECT 'Find and update row', DATEDIFF(ms, @StartTime, SYSDATETIME())
SET @StartTime = SYSDATETIME()
COMMIT TRANSACTION
SELECT 'Commit', DATEDIFF(ms, @StartTime, SYSDATETIME())
GO
Faça o mesmo novamente, mas emita e meça a reversão.
DECLARE
@StartTime DATETIME2
, @Rows INT
SET @Rows = 1
CHECKPOINT
DBCC DROPCLEANBUFFERS
BEGIN TRANSACTION
SET @StartTime = SYSDATETIME()
UPDATE
dbo.bar
SET
col2 = REPLICATE('B', 4000)
FROM
dbo.bar b
INNER JOIN
(
SELECT TOP(@Rows)
col1
FROM
dbo.foo
ORDER BY
NEWID()
) f
ON f.col1 = b.col1
OPTION (MAXDOP 1)
SELECT 'Find and update row', DATEDIFF(ms, @StartTime, SYSDATETIME())
SET @StartTime = SYSDATETIME()
ROLLBACK TRANSACTION
SELECT 'Rollback', DATEDIFF(ms, @StartTime, SYSDATETIME())
GO
Com @ Rows = 1, fico razoavelmente consistente:
Com @ linhas = 100:
Com @ linhas = 1000:
Voltar à pergunta original. Se você está medindo o tempo gasto para realizar o trabalho mais a confirmação, a reversão está diminuindo porque a maior parte desse trabalho é gasta na busca da linha a ser atualizada, na verdade não na modificação de dados. Se você estiver analisando a operação de consolidação isoladamente, deve ficar claro que a consolidação faz muito pouco "trabalho" como tal. Confirmar é "Estou pronto".
begin tran
apenas aumenta o contador de transações. Se eu entendi, o rdbms está executando todas as tarefas (une linhas, gera planos de execução ...) no COMMIT?
Para o Oracle, a reversão pode demorar muito mais do que o tempo necessário para fazer as alterações que estão sendo revertidas. Isso geralmente não importa porque
Para o SQL Server, não tenho certeza se a situação é a mesma, mas alguém dirá se não é ...
Quanto ao "porquê", eu diria que isso rollback
deve ser raro , geralmente apenas se algo der errado, e commit
é claro que provavelmente será muito mais comum - por isso, faz sentido otimizar paracommit
A reversão não é apenas "oh, não importa" - em muitos casos, ela realmente precisa desfazer o que já havia feito. Não há regra de que a operação de reversão seja sempre mais lenta ou sempre mais rápida que a operação original, embora, mesmo que a transação original tenha sido executada em paralelo, a reversão seja de thread único. Se você está esperando, sugiro que é mais seguro continuar esperando.
Isso tudo muda com o SQL Server 2019, é claro, e a Accelerated Database Recovery (que, com uma penalidade também variável) permite reversão instantânea, independentemente do tamanho dos dados.
Nem todas as transações terão sua atividade de confirmação com desempenho muito melhor que sua reversão. Um desses casos é a operação de exclusão no SQL. Quando uma transação exclui linhas, essas linhas são marcadas como registros fantasmas. Depois que uma confirmação é emitida e uma tarefa de limpeza de registro fantasma é iniciada, somente esses registros são 'excluídos'.
Se uma reversão foi emitida, ela remove as marcações fantasmas desses registros, e não as instruções de inserção intensivas.
Nem todos são. O PostgreSQL não demora mais para reverter do que para confirmar, pois as duas operações são efetivamente idênticas em termos de E / S do disco. Na verdade, não acho que seja uma questão de ser otimizado para o commit, mas sim para quais outras consultas estamos otimizando.
A questão básica é como você lida com o layout do disco e como isso afeta a confirmação versus a reversão. Os principais bancos de dados que retrocedem mais lentamente do que confirmam tendem a mover dados, principalmente de tabelas em cluster, para fora das principais estruturas de dados e colocá-los em um segmento de reversão ao atualizar dados. Isso significa que, para confirmar, basta descartar o segmento de reversão, mas, para reverter, é necessário copiar todos os dados.
Para o PostgreSQL, todas as tabelas são tabelas de heap e os índices são separados. Isso significa que, ao reverter ou confirmar, nenhum dado precisa ser reorganizado. Isso faz com que a consolidação e a reversão sejam rápidas.
No entanto, isso torna algumas outras coisas um pouco mais lentas. Uma pesquisa de chave primária, por exemplo, precisa percorrer um arquivo de índice e, em seguida, acessar a tabela de heap (supondo que não haja índices de cobertura aplicáveis). Isso não é um grande negócio, mas adiciona uma pesquisa de página extra ou talvez algumas pesquisas de página aleatórias (se muitas atualizações ocorreram nessa linha) para verificar outras informações e visibilidade.
A velocidade aqui, no entanto, não é uma questão de otimização no PostgreSQL para operações de gravação versus operações de leitura. É uma relutância em privilegiar algumas operações de leitura acima de outras. Consequentemente, o PostgreSQL executa, em média, tanto quanto os outros bancos de dados. Apenas algumas operações podem ser mais rápidas ou mais lentas.
Portanto, acho que a resposta real é que os bancos de dados são otimizados para determinadas cargas de trabalho no lado de leitura e isso leva a desafios no lado de gravação. Geralmente, onde há uma pergunta, os commits geralmente são, embora nem sempre, favorecidos em relação às reversões. No entanto, isso depende das implicações de se executar uma delas (as atualizações são diferentes das exclusões).