“UPDATE, INSERT e DELETE não são normalmente processados ​​em paralelo”

“UPDATE, INSERT e DELETE não são normalmente processados ​​em paralelo”

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br


Anos atrás, ao solucionar problemas de desempenho, me deparei com esta documentação da Microsoft sobre processamento de consulta paralela que diz:

Certos tipos de instruções não podem ser processados ​​em paralelo, a menos que contenham cláusulas, no entanto. Por exemplo, UPDATE, INSERT e DELETE não são normalmente processados ​​em paralelo, mesmo se a consulta relacionada atender aos critérios. Mas se as instruções UPDATE ou DELETE contêm uma cláusula WHERE, ou uma instrução INSERT contém uma cláusula SELECT, WHERE e SELECT podem ser executados em paralelo. As alterações são aplicadas em série ao banco de dados nesses casos.

Graças a Deus eu marquei, porque segui em frente com minha vida e me esqueci totalmente até recentemente. Tive de solucionar alguns problemas de exclusões lentas diferentes e, em ambos os casos, surgiram questões de paralelismo. Para ajudar a contar a história, reconstruí versões deles com o grande banco de dados Stack Overflow.

Achei que deveria blogar sobre isso porque fiz uma pesquisa no Twitter, e vocês também não tinham certeza:

E houve até desacordo entre vocês que tinham certeza, hahaha, então vamos examinar isso.

Problema 1: Limpar uma mesa

Digamos que você precise apagar periodicamente o conteúdo de uma tabela e começar de novo, e seu aplicativo não tem as permissões necessárias para fazer uma tabela truncada. No momento, tudo o que você está fazendo é uma simples exclusão:

O plano de execução não é bonito:

"UPDATE, INSERT e DELETE não são normalmente processados ​​em paralelo" 2

Qual é a aparência de 148.723 Query Bucks

Para esta demonstração, estou usando a tabela de 40 milhões de linhas e 105 GB de posts, e ela tem 13 índices. Esse banco de dados é o ponto de partida para as classes de Mastering – eu descarto diferentes índices nele dependendo do que o pessoal do laboratório está fazendo – e ele replica perfeitamente o tipo de problema que o cliente enfrentou.

Leia Também  [Video] Você pode dizer quando uma reversão será concluída?

O plano não tem operadores de paralelismo, o que por sua vez aquece um núcleo de CPU, o que então incendeia 148.723 dólares de consulta:

Fogueira das vaidades

Observando os planos de consulta ao vivo com sp_BlitzWho, podemos ver o SQL Server trabalhando por meio do plano, um índice por vez, classificando milhões de linhas de dados. Um índice de cada vez. Dois minutos, turco.

Esta consulta é de thread único, mas … podemos obter um operador paralelo qualquer lugar no plano e, em caso afirmativo, a consulta será mais rápida? Bem, podemos meio que ganhar paralelismo ao injetar um filtro sem sentido que corresponda a todas as linhas. Nesse caso, o SQL Server usa paralelismo para “buscar” em um índice, descobre que todas as linhas correspondem e, em seguida, começa a excluir. No entanto, não há paralelismo na operação de exclusão em si, apenas durante a operação sem sentido para “encontrar” as linhas que correspondem, o que é claro, todas elas. A exclusão não termina mais rápido.

Anyhoo, deixando de lado exemplos de acrobacias, de volta ao problema em si. Posso entender totalmente a frustração do desenvolvedor porque, com esse tipo de consulta, você pensaria que o SQL Server:

  • Retire um cadeado exclusivo na mesa
  • Comece excluindo o conteúdo de todos os índices em paralelo (já que cada linha em cada índice deve ser excluída e temos um bloqueio exclusivo na tabela, então não é como se precisássemos nos preocupar com a proteção do Halloween)

Nesse caso, ajuda a redefinir as perspectivas e dizer: “O verdadeiro problema aqui não é o paralelismo: simplesmente não deveríamos estar fazendo todo esse trabalho, muito menos espalhando-o por vários núcleos”. Melhores soluções para este problema específico:

  • Use a postagem de K. Brian Kelley sobre truncamento de tabelas com o mínimo de permissões e, em seguida, idealmente, use um procedimento armazenado assinado com certificado para realizar a ação suja
  • Se você não pode truncar a tabela, elimine-a e crie uma nova em seu lugar – o que tem todos os tipos de problemas em torno de segurança, chaves estrangeiras, objetos que podem ter sido adicionados à tabela (como índices e gatilhos)
  • Se você não pode fazer nada disso, pelo menos elimine todos os índices primeiro e, em seguida, recrie-os depois que a tabela estiver vazia (que é o que acabamos fazendo neste caso, bizarramente, porque apresentava menos problemas de segurança para aquele particular situação – às vezes o certo solução não é politicamente viável)
Leia Também  Column-level SQL Server encryption with SQL Server Always On Availability Groups

Problema 2: Limpando as partes de uma mesa

Truncar era óbvio, mas as coisas ficaram mais difíceis com a segunda consulta. Digamos que tenhamos outra tabela – usarei a linha 66M, a tabela Comentários de 22 GB neste exemplo. Digamos que executamos regularmente um projeto de limpeza que remove todos os comentários cuja pontuação é inferior à média geral:

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br

E digamos que não queremos adicionar um índice Score apenas para o processo de exclusão, porque o aplicativo não o usaria para qualquer outro propósito. O plano começa com duas varreduras da tabela de comentários – uma varredura para encontrar a pontuação média e outra varredura para encontrar as linhas que queremos excluir:

"UPDATE, INSERT e DELETE não são normalmente processados ​​em paralelo" 3

Um começo difícil

E todo o plano segue em um único segmento, apesar de custar 49.345 Query Bucks. Ai. (Curiosamente, é muito fácil obter paralelismo em consultas de exclusão como esta se você referenciar de outros tabelas, como se eu excluísse todas as linhas de comentários com uma pontuação inferior à pontuação média das postagens.)

Nesse caso, fazia sentido dividir a consulta em duas fases:

  1. Encontre a pontuação média dos comentários (e esse plano de consulta segue paralelo, e provavelmente faz sentido fazer separadamente antes do tempo de qualquer maneira)
  2. Exclua todos os comentários com uma pontuação inferior a essa (esse plano de consulta permanece com um único thread, mas isso realmente não importa – é apenas muito trabalho)

Essa mudança por si só nos levou a linha de chegada nesse caso.

Se essas soluções não tivessem sido suficientes

Para ajustes adicionais, poderíamos pensar em soluções como:

  • Particionamento por intervalos de pontuação
  • Projetar duas tabelas separadas: uma onde todos os novos comentários são inseridos e outra onde os comentários são movidos após atingirem um determinado limite de pontuação e, em seguida, truncar a tabela de pontuação baixa para acelerar o processo de exclusão.
  • Em vez de excluir, construir uma tabela CommentsToKeep, migrar sobre as linhas desejadas, descartar a tabela antiga de comentários e renomear CommentsToKeep como comentários

No entanto, todas essas soluções têm muitas desvantagens – e o ponto principal deste post foi apenas apontar que, só porque algo dá muito trabalho, não significa que vá funcionar em paralelo.

Se você estiver interessado neste tipo de coisa

Você provavelmente também gostará da série de Paul White sobre o problema do Halloween e do novo módulo Usando lotes para fazer muito trabalho sem bloquear da minha classe Mastering Query Tuning. Além disso, aqui está um exercício de pensamento divertido: se você tiver que fazer muitas dessas exclusões em tabelas diferentes, é melhor executá-las:

  • Serialmente, um após o outro, em um longo comando / batch / proc, ou
  • Em paralelo, em sessões diferentes, cada uma usando núcleos de CPU diferentes?

A resposta dependeria de coisas como:

  • Quão rápido é o seu subsistema de IO – como se um núcleo pode maximizá-lo
  • Que tipo de solução HA / DR você está usando – por exemplo, você realmente deseja inundar seu AG de várias sub-redes com 100 GB de alterações registradas em questão de minutos
  • Se o bloqueio vai mostrar sua cara feia – como se você tivesse chaves estrangeiras ou gatilhos