Pergunta

Temos uma consulta para remover algumas linhas da tabela com base em um campo id (chave primária). É uma consulta bastante simples:

delete all from OUR_TABLE where ID in (123, 345, ...)

O problema é No.of ids pode ser enorme (Ex. 70k), de modo a consulta leva um longo tempo. Existe alguma maneira de otimizar isso? (Estamos usando Sybase - se o que importa).

Foi útil?

Solução

Considere executar isso em lotes. Um loop correndo 1000 registros em um momento pode ser muito mais rápido do que uma consulta que faz tudo e, além disso não vai manter a tabela bloqueada para outros usuários durante o tempo em um trecho.

Se você tiver exclusão em cascata (e muitas mesas de chaves estrangeiras afetadas) ou gatilhos envolvido, você pode precisar executar em lotes ainda menores. Você vai ter que experiement para ver qual é o melhor número para a sua situação. Eu tive mesas onde eu tive que excluir em lotes de 100 e outros onde 50000 trabalhados (sorte, nesse caso, como eu estava exclusão de um milhão de discos).

Mas, em qualquer, mesmo que eu iria colocar meus valores-chave que tenho a intenção de excluir em uma tabela temporária e excluir de lá.

Outras dicas

Há duas maneiras de fazer declarações como este executar:

  1. Criar uma nova tabela e copiar todos, mas as linhas para eliminar. Trocar as mesas depois (alter table name ...) eu sugiro para dar-lhe uma tentativa, mesmo quando soa estúpido. Alguns bancos de dados são muito mais rápidos em copiar do que em exclusão.

  2. Partition suas tabelas. Criar tabelas N e usar a fim de se juntar a eles em um só. Ordenar as linhas em tabelas diferentes agrupados pelo critério de exclusão. A idéia é deixar cair uma tabela inteira em vez de excluir linhas individuais.

Eu estou querendo saber se a análise de uma cláusula IN com 70K itens em que é um problema. Você já tentou uma tabela temporária com uma associação em vez?

Can Sybase punho 70K argumentos na cláusula IN? Todos os bancos de dados que eu trabalhei com ter algum limite no número de argumentos para cláusula IN. Por exemplo, a Oracle tem limite por volta de 1000.

Você pode criar subselect em vez de cláusula IN? Isso vai encurtar sql. Talvez isso poderia ajudar para um número tão grande de valores na cláusula IN. Algo parecido com isto:

  DELETE FROM OUR_TABLE WHERE ID IN 
        (SELECT ID FROM somewhere WHERE some_condition)

Apagar grande número de registros pode ser acelerado com algumas intervenções no banco de dados, Se houver modelo de banco de dados. Aqui estão algumas estratégias:

  1. Você pode acelerar as coisas, largando índices, excluir registros e recriando índices novamente. Isto irá eliminar árvores índice reequilíbrio ao excluir registros.

    • soltar todos os índices na tabela
    • registros excluir
    • índices Recriar
    • Se você tem muitas relações com esta tabela, tente desabilitar restrições se você tem certeza absoluta de que comando delete não vai quebrar qualquer restrição de integridade. Excluir vai muito mais rápido, porque banco de dados não será verificação de integridade. Ativar restrições após a exclusão.
    • Desativar restrições de integridade, restrições de verificação desativar
    • registros excluir
    • permitem restrições
    • desativar os gatilhos das mesa, se você tiver qualquer e se suas regras de negócios permitir isso. excluir registros, em seguida, permitir que gatilhos.

    • passado, fazer como outros sugeridas - fazer uma cópia da tabela que contém linhas que não estão a ser excluído, em seguida, solte original, renomear copiar e integridade recriar as restrições, se houver algum.

Gostaria de tentar combinação de 1, 2 e 3. Se isso não funcionar, em seguida, 4. Se tudo é lento, eu iria procurar maior caixa -. Mais memória, discos mais rápidos

Saiba o que está usando-se o desempenho!

Em muitos casos, você pode usar uma das soluções fornecidas. Mas pode haver outros (com base no Oracle conhecimento, então as coisas vão ser diferentes em outros bancos de dados Edit:. Acabou de ver que você mencionou Sybase):

  • Você tem chaves estrangeiras nessa tabela? Garante que o ids referentes são indexados
  • Você tem índices nessa tabela? Pode ser que droping antes de apagar e recriar após a exclusão pode ser mais rápido.
  • verificar o plano de execução. É utilizando um índice onde uma varredura completa da tabela pode ser mais rápido? Ou do outro modo? DICAS pode ajudar
  • em vez de uma escolha em new_table como sugerido acima a criar a tabela como selecionar pode ser ainda mais rápido.

Mas lembre-se:. Descubra o que está usando-se o desempenho primeira

Quando você estiver usando instruções DDL certifique-se de compreender e aceitar as consequências que pode ter sobre as transações e backups.

Tente classificar a ID que você está passando para "in" na mesma ordem que a tabela ou índice é armazenado em. Você pode, então, obter mais hits no cache de disco.

Colocar o ID a ser eliminado em uma tabela temporária que os IDs classificadas na mesma ordem como a tabela principal, pode deixar o banco de dados de fazer um simples digitalizado sobre a mesa principal.

Você pode tentar usar mais de uma conexão e spiting o trabalho sobre as conexões de modo a utilizar todas as CPUs no servidor de banco de dados, no entanto, pensar sobre o que fechaduras será retirado etc em primeiro lugar.

Eu também acho que a tabela temporária é provavelmente a melhor solução.

Se você fosse fazer um "excluir .. onde ID no (id selecione a partir de ...)" ele ainda pode ser lento, com consultas grandes, no entanto. Eu, portanto, sugiro que você excluir usando uma junção - muitas pessoas não sabem sobre essa funcionalidade

.

Assim, dada esta tabela exemplo:

    -- set up tables for this example
    if exists (select id from sysobjects where name = 'OurTable' and type = 'U')
        drop table OurTable
    go

    create table OurTable (ID integer primary key not null)
    go
    insert into OurTable (ID) values (1)
    insert into OurTable (ID) values (2)
    insert into OurTable (ID) values (3)
    insert into OurTable (ID) values (4)
    go

Podemos então escrever nosso código de exclusão da seguinte forma:

    create table #IDsToDelete (ID integer not null)
    go
    insert into #IDsToDelete (ID) values (2)
    insert into #IDsToDelete (ID) values (3)
    go
    -- ... etc ...
    -- Now do the delete - notice that we aren't using 'from'
    -- in the usual place for this delete
    delete OurTable from #IDsToDelete
       where OurTable.ID = #IDsToDelete.ID
    go
    drop table #IDsToDelete
    go
    -- This returns only items 1 and 4
    select * from OurTable order by ID
    go

O our_table ter uma referência em cascata de exclusão?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top