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 / 190140
Accepted
Alexei
Alexei
Asked: 2017-11-06 02:23:49 +0800 CST2017-11-06 02:23:49 +0800 CST 2017-11-06 02:23:49 +0800 CST

Por que meu comando DELETE requer uma grande quantidade de armazenamento temporário de execução?

  • 772

Estou tentando realizar uma operação de limpeza em uma tabela usando DELETEe recebo o seguinte erro:

Não foi possível alocar espaço para armazenamento temporário de execução do objeto 'dbo.SORT: 140767697436672' no banco de dados 'tempdb' porque o grupo de arquivos 'PRIMARY' está cheio. Crie espaço em disco excluindo arquivos desnecessários, descartando objetos no grupo de arquivos, adicionando arquivos adicionais ao grupo de arquivos ou definindo o crescimento automático para arquivos existentes no grupo de arquivos.

Antes de executar o DELETEtenho mais de 11G de espaço livre em disco. Quando o erro é emitido, não tenho quase nada nessa partição. As informações de contexto estão abaixo:

1) Consulta problemática:

declare @deleteDate DATETIME2 = DATEADD(month, -3, GETDATE()) 
delete from art.ArticleConcept where ArticleId IN (select ArticleId from art.Article where PublishDate < @deleteDate)

2) Cardinalidade para tabelas envolvidas

declare @deleteDate DATETIME2 = DATEADD(month, -3, GETDATE())
select count(1) from art.Article    -- 137181
select count(1) from art.Article where PublishDate < @deleteDate    -- 111450
select count(1) from art.ArticleConcept where ArticleId IN (select ArticleId from art.Article where PublishDate < @deleteDate)      -- 12153045
exec sp_spaceused 'art.ArticleConcept'
-- name             rows       reserved     data        index_size   unused
-- ArticleConcept   14624589   1702000 KB   616488 KB   1084272 KB   1240 KB

3) Índices

-- index_name   index_description   index_keys
-- IDX_ArticleConcept_ArticleId_Incl_LexemId_Freq   nonclustered located on PRIMARY ArticleId

CREATE NONCLUSTERED INDEX [IDX_ArticleConcept_ArticleId_Incl_LexemId_Freq] ON [art].[ArticleConcept]
(
[ArticleId] ASC
)
INCLUDE (   [LexemId],
[Freq]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)

4) Servidor

Select @@version
-- Microsoft SQL Server 2014 - 12.0.2000.8 (X64) 
-- Feb 20 2014 20:04:26 
-- Copyright (c) Microsoft Corporation
-- Express Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: ) (Hypervisor)

5) Plano de execução (estimado)

Plano de execução

Entendo que estou executando um DELETE grande, mas não consigo entender por que isso requer tanto espaço: a ArticleConcepttabela inteira tem menos de 2 GB (espaço reservado), mas para remover registros dela é necessário mais de 11 GB.

Pergunta: Por que meu comando DELETE requer uma grande quantidade de armazenamento temporário de execução?

Eu removi todos os índices secundários e pude executar o DELETE. No entanto, por que é necessário tanto mais espaço para realizar as tarefas DELETEao tê-las, parece-me estranho.

Estou tentando excluir 12.153.045 de 14.624.589 registros (muitos). Não monitorei o log de transações, mas uma vez recebi um erro relacionado a ele:

O log de transações do banco de dados... está cheio devido a 'ACTIVE_TRANSACTION'

sql-server sql-server-2014
  • 3 3 respostas
  • 1277 Views

3 respostas

  • Voted
  1. Best Answer
    Joe Obbish
    2017-11-06T16:30:19+08:002017-11-06T16:30:19+08:00

    Há sete operadores no plano de consulta que podem se espalhar para tempdb. Eu os numerei abaixo:

    numerado

    A subconsulta select ArticleId from art.Article where PublishDate < @deleteDatefoi implementada como junção entre dois índices não clusterizados pelo otimizador de consulta. A junção é uma junção de hash que requer que uma tabela de hash seja construída no rótulo 1 . É possível que a tabela de hash seja derramada no tempdb. Para sua consulta, a tabela de hash tem apenas cerca de 100 mil linhas, portanto, não é provável que seja o problema.

    A junção entre ArticleConcepte Articleé implementada como uma junção de mesclagem. Ambas as entradas de junção precisam ser classificadas para a junção que resulta na classificação vista no rótulo 2 . Essa classificação só precisa processar cerca de 100 mil linhas.

    Uma classificação é feita no rótulo 3 para melhorar o desempenho da exclusão. Os dados serão classificados na ordem das chaves do índice clusterizado da tabela. Você está excluindo cerca de 12 milhões de linhas, então espero que classifique as chaves agrupadas de 12 milhões de linhas. Isso pode se espalhar para o tempdb.

    A tabela de destino da exclusão possui índices não clusterizados. O otimizador de consulta tem alguns métodos diferentes para implementar as atualizações nos índices. Ele escolhe uma atualização ampla por índice . Isso é feito com base no custo e provavelmente ocorre porque você está excluindo uma grande porcentagem de linhas da tabela de destino. O spool de tabela no rótulo 4 contém todas as chaves de índice junto com as chaves de índice clusterizadas. Ele armazenará 12 milhões de linhas e gravará em tempdb.

    As classificações nos rótulos 5 , 6 e 7 são para classificar os dados na ordem das chaves de índice e das chaves de índice clusterizado de cada índice não clusterizado. É provável que esses tipos estejam vazando para o tempdb.

    Todos esses derramamentos se somam. Se você tiver um tipo de 1 GB de dados no disco e esse tipo de derramamento no disco, ele não consumirá necessariamente exatamente 1 GB de espaço tempdb. Na minha experiência, geralmente requer mais espaço no tempdb do que no disco.

    Mesmo que a consulta não tenha falhado, ainda não é a abordagem mais ideal. A exclusão de 12 milhões de linhas de uma tabela de 14 milhões de linhas do índice clusterizado e três índices não clusterizados é muito trabalhoso. Seria mais eficiente inserir as linhas para manter em outra tabela, construir os índices não clusterizados nessa tabela e alternar as tabelas no lugar. Como você mesmo viu, descartar os índices não clusterizados antes da exclusão e recriá-los após a exclusão pode ser suficiente. As soluções alternativas descritas aqui só devem ser feitas durante uma janela de manutenção quando os usuários finais não estiverem acessando os dados.

    • 4
  2. alroc
    2017-11-06T05:06:16+08:002017-11-06T05:06:16+08:00

    Você precisa agrupar suas exclusões para não bloquear a tabela e preencher seu log de transações.

    declare @deleteDate DATETIME2 = DATEADD(month, -3, GETDATE()) 
     DECLARE    
        @RC INT = 1;
     
    WHILE (@RC > 0)
    BEGIN
     
      delete top 1000 art.ArticleConcept 
       where ArticleId 
          IN (select ArticleId 
                from art.Article 
               where PublishDate < @deleteDate);
     
      SET @RC = @@ROWCOUNT
     
    END
    

    Você pode experimentar tamanhos de lote maiores (geralmente 5000-50000), mas este é um bom lugar para começar. Você precisa ter cuidado com as tentativas de escalonamento de bloqueio ao escolher tamanhos de lote.

    Você provavelmente também verá uma melhoria enviando sua lista de ArticleIds para uma tabela temporária para que você só precise digitalizar art.Articleuma vez.

    declare @deleteDate DATETIME2 = DATEADD(month, -3, GETDATE()) 
    
    create table #ArticlesToDelete 
           (ArticleId int primary key not null);
    
    insert into #ArticlesToDelete (ArticleId) 
    select ArticleId 
      from art.Article 
     where PublishDate < @deleteDate;
    
    DECLARE @RC INT = 1;
     
    WHILE (@RC > 0)
    BEGIN
    
      delete top 1000 A 
        from art.ArticleConcept A 
        join #ArticlesToDelete D 
          on A.ArticleId = D.ArticleId;
    
      SET @RC = @@ROWCOUNT
    
    END
    
    drop table #ArticlesToDelete
    
    • 3
  3. KumarHarsh
    2017-11-08T19:41:54+08:002017-11-08T19:41:54+08:00

    O principal problema é que não há coluna de data no art.ArticleConcept.

    Além disso, você deve sempre compartilhar a estrutura da tabela de ambas as tabelas.

    Excluir Bacthwise também é bom.

    Acho que @Joe sugeriu o mesmo método abaixo

    declare @deleteDate DATETIME2 = DATEADD(month, -3, GETDATE()) 
    
    --Test this several time and mention column name instead of *
    Select * into art.NewArticleConcept
    from  art.ArticleConcept AC WITH (NOLOCK)
    where exists 
    (select ArticleId from art.Article A WITH (NOLOCK)
    where a.ArticleId =ac.ArticleId and  PublishDate >= @deleteDate)
    
    --Then
    drop table art.ArticleConcept
    
    --Then rename newly created table to old table name
    sp_rename art.NewArticleConcept art.ArticleConcept
    
    --Create index on art.ArticleConcept
    
        CREATE NONCLUSTERED INDEX [IDX_ArticleConcept_ArticleId_Incl_LexemId_Freq] 
     ON [art].[ArticleConcept]
        (
        [ArticleId] ASC
        )
        INCLUDE (   [LexemId],
        [Freq]) 
    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
          SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, 
          ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
    

    A principal vantagem da abordagem acima é que você não precisa recuperar espaço ou reconstruir o índice ou reconstruir as estatísticas.

    Se Select * intoa parte não for problemática, vá em frente.

    Além disso, você tem que criar Covering indexna art.ArticleConcepttabela.

    • 1

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