Pergunta

Eu tenho uma tabela DB em que cada linha tem uma chave primária gerada aleatoriamente, uma mensagem e um usuário. Cada usuário tem cerca de 10-100 mensagens, mas existem 10k-50k usuários.

Eu escrevo as mensagens diárias para cada usuário de uma só vez. Eu quero jogar fora as velhas mensagens para cada usuário antes de escrever os novos para manter a tabela tão pequena quanto possível.

Agora eu efetivamente fazer isso:

delete from table where user='mk'

Em seguida, escreva todas as mensagens para o usuário. Eu estou vendo um monte de contenção, porque eu tenho um monte de tópicos fazendo isso ao mesmo tempo.

Eu tenho um requisito adicional para reter o conjunto mais recente de mensagens para cada usuário.

Eu não tenho acesso ao DB diretamente. Estou tentando adivinhar o problema com base em alguma segunda medição mão. A razão que eu estou focando neste cenário é que a consulta de exclusão está mostrando um monte de tempo de espera (mais uma vez - para o melhor de meu conhecimento). Além disso, é um pouco recém-adicionado de funcionalidade

Alguém pode oferecer algum conselho?

Seria melhor para:

select key from table where user='mk'

linhas individuais em seguida, elimine a partir daí? Estou pensando que pode levar a bloqueio menos brutal.

Foi útil?

Solução

Não, é sempre melhor para executar uma única instrução SQL em um conjunto de linhas que uma série de "linha por linha" (ou o que Tom Kyte chama de "slow-by-lentas") operações. Quando você diz que é "vendo um monte de contenção", o que está vendo exatamente? Uma pergunta óbvia: é USUÁRIO coluna indexada

(Claro, o nome da coluna não pode realmente ser usuário em um banco de dados Oracle, uma vez que é uma palavra reservada!)

EDIT: Você disse que USUÁRIO coluna não é indexado. Isto significa que cada exclusão vai envolver uma varredura completa da tabela de até 50K * 100 = 5 milhões de linhas (ou na melhor das hipóteses 10K * 10 = 100.000 linhas) para excluir um mero 10-100 linhas. Adicionando um índice em USUÁRIO pode resolver seus problemas.

Outras dicas

Se você fizer isso todos os dias para cada usuário, porque não basta apagar todos os registros da tabela em uma única instrução? Ou mesmo

truncate table whatever reuse storage
/

Editar

A razão pela qual eu sugiro que esta abordagem é que o processo se parece com um carregamento de lote diário de mensagens do usuário precedido por uma clareira fora das mensagens antigas. Ou seja, as regras de negócio parece-me ser "a mesa irá realizar vale apenas um dia de mensagens para qualquer usuário". Se este processo é feito para cada usuário, em seguida, uma única operação seria o mais eficiente.

No entanto, se os usuários não obter um novo conjunto de mensagens a cada dia e existe uma regra subsidiária que nos obriga a manter o conjunto mais recente de mensagens para cada usuário, em seguida, zapping a tabela inteira seria estar errado.

Você tem certeza de que você está vendo contenção de bloqueio? Parece mais provável que você está vendo a contenção de disco devido a muitos concorrentes (mas as atualizações não relacionadas). A solução para isso é simplesmente para reduzir o número de threads que você está usando:. Menos contenção de disco significará débito total superior

Eu acho que você precisa definir suas necessidades um pouco mais claro ...

Por exemplo. Se você sabe que todos os usuários que você deseja escrever mensagens para, inserir os IDs em uma tabela temporária, indexá-lo na identificação e exclusão em lote. Em seguida, os tópicos que você está atirando fora estão fazendo duas coisas. Escreva o ID do usuário para uma tabela temporária, escrever a mensagem para outra tabela temporária. Então, quando os fios tenham terminado a execução, o principal segmento deve

* DELETE FROM Mensagens INNER JOIN TEMP_MEMBERS ON ID = TEMP_ID

MENSAGENS INSERT INTO SELECT * FROM TEMP_messges

im não familiarizado com a sintaxe Oracle, mas essa é a maneira que eu iria abordá-lo se as mensagens de usuários são todas feitas em rápida sucessão.

Espero que isso ajude

Fale com o seu DBA

Ele está lá para ajudá-lo. Quando DBAs ter acesso longe dos desenvolvedores para algo como isso, presume-se que irá fornecer o apoio para você para essa tarefa. Se o seu código está demorando muito para ser concluído e que o tempo parece ser amarrado no banco de dados, o DBA será capaz de olhar exatamente o que está acontecendo e oferecer sugestões ou possivelmente até mesmo resolver o problema sem você mudar nada.

Apenas olhando por cima do seu enunciado do problema, não parece que você estaria olhando para problemas de contenção, mas eu não sei nada sobre a sua estrutura subjacente.

Na verdade, falar com o seu DBA. Ele provavelmente irá desfrutar olhando para algo divertido, em vez de planejar a última implantação CPU.

Esta velocidade força as coisas:

Criar uma tabela de pesquisa:

create table rowid_table (row_id ROWID ,user VARCHAR2(100));
create index rowid_table_ix1 on rowid_table (user);

Executar um trabalho noturno:

truncate table rowid_table;
insert /*+ append */ into rowid_table
select ROWID row_id , user
from table;
dbms_stats.gather_table_stats('SCHEMAOWNER','ROWID_TABLE');

Em seguida, ao excluir os registros:

delete from table
where ROWID IN (select row_id
                from rowid_table
                where user = 'mk');

A sua própria sugestão parece muito sensato. Bloqueio em pequenos lotes tem duas vantagens:

  • as transações serão menores
  • bloqueio será limitado a apenas algumas linhas de cada vez

O bloqueio em lotes deve ser uma grande melhoria.

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