No sistema em que trabalho existem muitos procedimentos armazenados e scripts SQL que fazem uso de tabelas temporárias. Depois de usar essas tabelas, é uma boa prática eliminá-las.
Muitos dos meus colegas (quase todos são muito mais experientes do que eu) costumam fazer isso:
TRUNCATE TABLE #mytemp
DROP TABLE #mytemp
Eu normalmente uso um single DROP TABLE
em meus scripts.
Existe alguma boa razão para fazer um TRUNCATE
imediatamente antes de um DROP
?
Não.
TRUNCATE
eDROP
são quase idênticos em comportamento e velocidade, então fazer umTRUNCATE
direito antes de aDROP
é simplesmente desnecessário.Observação: escrevi esta resposta de uma perspectiva do SQL Server e presumi que ela se aplicaria igualmente ao Sybase. Parece que este não é inteiramente o caso .
Nota: Quando publiquei esta resposta pela primeira vez, havia várias outras respostas altamente avaliadas - incluindo a resposta então aceita - que fizeram várias alegações falsas como:
TRUNCATE
não está registrado;TRUNCATE
não pode ser revertido;TRUNCATE
é mais rápido queDROP
; etc.Agora que este tópico foi limpo, as refutações que se seguem podem parecer tangenciais à pergunta original. Deixo-os aqui como referência para outros que procuram desmascarar esses mitos.
Existem algumas falsidades populares - difundidas mesmo entre DBAs experientes - que podem ter motivado esse
TRUNCATE-then-DROP
padrão. Eles são:TRUNCATE
não é registrado, portanto, não pode ser revertido.TRUNCATE
é mais rápido queDROP
.Deixe-me refutar essas falsidades. Estou escrevendo esta refutação da perspectiva do SQL Server, mas tudo o que digo aqui deve ser igualmente aplicável ao Sybase.
TRUNCATE é registrado e pode ser revertido.
TRUNCATE
é uma operação registrada, portanto , pode ser revertida . Basta envolvê-lo em uma transação.Observe, no entanto, que isso não é verdade para o Oracle . Embora registrado e protegido pela funcionalidade de desfazer e refazer do Oracle,
TRUNCATE
e outras instruções DDL não podem ser revertidas pelo usuário porque o Oracle emite confirmações implícitas imediatamente antes e depois de todas as instruções DDL.TRUNCATE
é minimamente registrado , em vez de totalmente registrado. O que isso significa? Diga-lheTRUNCATE
uma mesa. Em vez de colocar cada linha excluída no log de transações,TRUNCATE
apenas marca as páginas de dados em que elas residem como não alocadas. Por isso é tão rápido. É também por isso que você não pode recuperar as linhas de umaTRUNCATE
tabela -ed do log de transações usando um leitor de log. Tudo o que você encontrará são referências às páginas de dados desalocadas.Compare isso com
DELETE
. Se vocêDELETE
todas as linhas em uma tabela e confirma a transação, ainda pode, em teoria, encontrar as linhas excluídas no log de transações e recuperá-las de lá. Isso porqueDELETE
grava cada linha excluída no log de transações. Para tabelas grandes, isso o tornará muito mais lento do queTRUNCATE
.DROP é tão rápido quanto TRUNCATE.
TRUNCATE
,DROP
é uma operação minimamente registrada. Isso significa queDROP
pode ser revertido também. Isso também significa que funciona exatamente da mesma maneira que oTRUNCATE
. Em vez de excluir linhas individuais,DROP
marca as páginas de dados apropriadas como não alocadas e marca adicionalmente os metadados da tabela como excluídos .Porque
TRUNCATE
eDROP
funcionam exatamente da mesma maneira, eles correm tão rápido quanto o outro. Não faz sentidoTRUNCATE
usar -ing em uma tabela antesDROP
de -ing-la. Execute este script de demonstração em sua instância de desenvolvimento se você não acredita em mim.Na minha máquina local com um cache quente, os resultados que obtenho são os seguintes:
Portanto, para uma tabela de 134 milhões de linhas, não demora muito. (Em um cache frio , eles levam cerca de 2-3 segundos para a primeira execução ou duas) . ordem de magnitude pior do que as operações individuais. Afinal, são quase exatamente a mesma coisa.
DROP
TRUNCATE
TRUNCATE
DROP
Se você estiver interessado em mais detalhes sobre a sobrecarga de log dessas operações, Martin tem uma explicação direta sobre isso.
Testar
TRUNCATE
entãoDROP
versus apenas fazer oDROP
diretamente mostra que a primeira abordagem realmente tem uma pequena sobrecarga de registro, portanto, pode até ser levemente contraproducente.Observar os registros de log individuais mostra que a
TRUNCATE ... DROP
versão é quase idêntica àDROP
versão, exceto por essas entradas adicionais.Então a
TRUNCATE
primeira versão acaba desperdiçando um pouco de esforço fazendo algumas atualizações em várias tabelas do sistema como seguercmodified
para todas as colunas da tabela emsys.sysrscols
rcrows
emsysrowsets
pgfirst
,pgroot
,pgfirstiam
,pcused
,pcdata
,pcreserved
emsys.sysallocunits
Essas linhas da tabela do sistema só acabam sendo excluídas quando a tabela é descartada na próxima instrução.
Um detalhamento completo do registro realizado por
TRUNCATE
vsDROP
está abaixo. Eu também adicioneiDELETE
para fins de comparação.O teste foi realizado em um banco de dados com modelo de recuperação total contra uma tabela de 1.000 linhas com uma linha por página. A tabela consome 1.004 páginas no total devido à página de índice raiz e 3 páginas de índice de nível intermediário.
8 dessas páginas são alocações de página única em extensões mistas, com o restante distribuído em 125 extensões uniformes. As 8 desalocações de página única aparecem como as 8
LOP_MODIFY_ROW,LCX_IAM
entradas de log. As desalocações de 125 extensões comoLOP_SET_BITS LCX_GAM,LCX_IAM
. Ambas as operações também requerem uma atualização para a página associada , portanto, as 133 entradasPFS
combinadas .LOP_MODIFY_ROW, LCX_PFS
Então, quando a tabela é realmente descartada, os metadados sobre ela precisam ser removidos de várias tabelas do sistema, portanto, as 22LOP_DELETE_ROWS
entradas de log da tabela do sistema (contabilizadas abaixo)Roteiro completo abaixo
OK, pensei em tentar fazer alguns benchmarks que não dependessem de nenhum "cache quente" para que, esperançosamente, fossem um teste mais realista (também usando o Postgres, para ver se ele corresponde às mesmas características de outras respostas postadas) :
Meus benchmarks usando o postgres 9.3.4 com um banco de dados grande (espero que seja grande o suficiente para não caber no cache da RAM):
Usando este script de banco de dados de teste: https://gist.github.com/rdp/8af84fbb54a430df8fc0
com 10 milhões de linhas:
com 100 milhões de linhas:
Então, a partir disso, suponho o seguinte: drop é "quase" tão rápido (ou mais rápido) quanto truncate + drop (pelo menos para versões modernas do Postgres), no entanto, se você planeja também virar e recriar a tabela, você pode bem, continue fazendo um truncate direto, que é mais rápido que um drop+recreate (faz sentido). FWIW.
nota 1: https://stackoverflow.com/questions/11419536/postgresql-truncation-speed/11423886#11423886 (diz que o postgres 9.2 pode ter um truncado mais rápido do que as versões anteriores). Como sempre, faça um benchmark com seu próprio sistema para ver suas características.
nota 2: truncate pode ser revertido no postgres, se estiver em uma transação: http://www.postgresql.org/docs/8.4/static/sql-truncate.html
nota 3: truncar pode, com tabelas pequenas, às vezes ser mais lento que uma exclusão: https://stackoverflow.com/questions/11419536/postgresql-truncation-speed/11423886#11423886
Adicionando alguma perspectiva histórica ...
A eliminação de uma tabela requer a atualização de várias tabelas do sistema, o que normalmente requer fazer essas alterações na tabela do sistema em uma única transação (pense em "começar tran, excluir syscolumns, excluir sysobjects, confirmar").
Também está incluída na 'tabela de descarte' a necessidade de desalocar todas as páginas de dados/índice associadas à tabela.
Muitos, muitos, muitos anos atrás ... o processo de desalocação de espaço foi incluído na transação que também atualizou as tabelas do sistema; o resultado líquido foi que quanto maior o número de páginas alocadas, mais tempo levava para desalocar as referidas páginas, maior o transação (nas tabelas do sistema) foi deixada em aberto e, portanto, uma chance maior de bloquear (nas tabelas do sistema) outros processos tentando criar/descartar tabelas no tempdb (especialmente desagradável com o allpages== bloqueio de nível de página mais antigo e potencial para tabela -nível de escalonamento de bloqueio).
Um método inicial usado (na época) para reduzir a contenção nas tabelas do sistema era reduzir o tempo que os bloqueios eram mantidos nas tabelas do sistema, e uma maneira (relativamente) fácil de fazer isso era desalocar as páginas de dados/índice antes de descartar a mesa.
Embora
truncate table
não desaloque todas as páginas de dados/índice, ele desaloca todas, exceto uma extensão de 8 páginas (dados); outro 'hack' foi descartar todos os índices antes de descartar a tabela (sim, separar txn em sysindexes, mas um txn menor para descartar tabela).Quando você considera que (novamente, muitos, muitos anos atrás) havia apenas um único banco de dados 'tempdb', e alguns aplicativos faziam uso PESADO desse único banco de dados 'tempdb', quaisquer 'hacks' que pudessem reduzir a contenção nas tabelas do sistema em 'tempdb' foram benéficos; com o tempo, as coisas melhoraram ... vários bancos de dados temporários, bloqueio de nível de linha nas tabelas do sistema, melhores métodos de desalocação, etc.
Enquanto isso, o uso do
truncate table
não faz mal se for deixado no código.Talvez haja uma razão histórica e temporária. Antes do Postgres 9.3 EVENTS TRIGGER não existe e você não podia "ON DROP" TRIGGER.
Mas a partir do Postgres 8.4 é possível fazer TRIGGER
ON TRUNCATE
Então talvez algumas pessoas que fariam alguma coisa especial tenham usado oTRIGGER ON TRUNCATE
para simular oON DROP
e para garantir a ativação do gatilho eles fazem TRUNCATE e depois DROP.Faz sentido fazer TRUNCATE para tabelas que possuem chaves estrangeiras. No entanto, para tabelas temporárias apenas DROP é suficiente
O objetivo do
truncate
é remover de forma simples e irrevogável tudo na tabela (algumas especificações técnicas baseadas em mecanismos de armazenamento de dados podem diferir um pouco) - pulando registros pesados, etc.drop table
registra todas as alterações à medida que as alterações estão sendo feitas. Portanto, para ter um registro mínimo e reduzir a rotatividade inútil do sistema, eu suspeitaria que uma tabela muito grande poderia ser truncada primeiro e depois descartada.truncate
pode ser envolvido em uma transação (que seria a opção mais segura) que, é claro, permitirá reverter a operação.