Recriar índice de chave primária muito grande

13

Eu tenho um banco de dados SQL hospedado no Azure. O problema é que o tamanho está ficando fora de controle. Posso ver até 99% de fragmentação nos índices de cluster da Chave Primária.

Sou capaz de reconstruir todos os outros índices com a online=onopção e isso não afeta o desempenho. O tamanho de um dos índices PK Clustered é maior que 200 GB e, nesse caso, REBUILD...WITH (ONLINE=ON)causa um bloqueio.

Temos usuários de todos os fusos horários acessando o site, então, não consigo encontrar um horário para reconstruir o índice offline.

Qual é a melhor estratégia para reconstruir índices grandes sem ter um tempo de inatividade no site?

Acredito que a reorganização não ajudará, pois a fragmentação é de 99%. O problema é que a tabela fica bloqueada mesmo com a online. O principal problema é que o índice é maior que 200 GB. A chave primária é um número inteiro.

Techy
fonte
4
O @Techy, mesmo com alta fragmentação, REORGANIZEreduzirá a fragmentação das páginas em folhas e o espaço compacto REBUILD, apenas com menos eficiência. Você tem certeza de que o tamanho grande é devido à fragmentação? Qual é o fator de preenchimento?
Dan Guzman
Você sabe o que está causando a fragmentação? Quanto tempo após a sua reconstrução você estará de volta ao ponto 1? Você pode postar mais informações sobre sua mesa?
pacreely
2
@ Techy Editei a pergunta para adicionar algumas informações adicionais com base em seus comentários. Seria útil se você também incluísse a definição da tabela na pergunta e detalhes adicionais relacionados a "a tabela fica bloqueada mesmo quando [reconstruindo] on-line". Que tipo de espera você está vendo?
AMtwo

Respostas:

9

Mesmo que seja um pouco tarde, vou responder com a esperança de que ajude ou pelo menos rejeite algumas idéias / comentários adicionais sobre esse assunto, porque acho que é uma boa pergunta.

Primeiro, e não sei se você está fazendo isso ou não, mas por favor, não assuma que altos níveis de fragmentação no índice sempre causam desempenho ruim. Estatísticas antigas (por exemplo, sys.dm_db_stats_properties ) e grandes quantidades de espaço em branco por página (por exemplo, avg_page_space_used_in_percent na coluna sys.dm_db_index_physical_stats dmv ) têm mais relevância em relação aos problemas de desempenho do que apenas à fragmentação. Sim, índices altamente fragmentados geram mais leituras antecipadas e você normalmente vê estatísticas obsoletas e níveis mais altos de espaço em branco por página, juntamente com a fragmentação, mas a fragmentação não está diretamente ligada às otimizações do plano de consulta nem à quantidade de memória que carrega o índice do disco vai realmente consumir. Os planos de consulta são afetados pelas estatísticas e sua pegada de memória incha com mais espaço em branco . Por exemplo, um índice fragmentado em 99%, mas com menos de 5% em média. É provável que o espaço em branco e as estatísticas atualizadas não estejam causando problemas drásticos de desempenho em comparação com um plano de execução ruim como resultado de estatísticas obsoletas ou paginação constante de um índice grande demais para caber na memória porque há uma quantidade significativa de espaço em branco presente por página.

Se a fragmentação é realmente um problema , você pode reduzi-la, online, emitindo uma ALTER INDEX ... REORGANIZEdeclaração conforme identificado por Dan Guzman nos comentários. Isso não criará um índice tão otimizado quanto uma REBUILDoperação, mas reduzirá sua fragmentação. A chave aqui é identificar janelas de menor uso em seu banco de dados e executá-lo. Isso pode levar 15 minutos ou várias horas, obviamente quanto mais, melhor, mas a chave aqui é que essa operação não reverte e retém qualquer progresso feito, mesmo que você a mate no meio da execução.

Se, em um mundo perfeito onde sua fragmentação foi eliminada, faria mais sentido utilizar o particionamento nesta tabela? O Banco de Dados SQL do Azure permite o particionamento de tabela e a Microsoft tem um ótimo artigo descrevendo algumas estratégias de particionamento para o Banco de Dados SQL do Azure . Se seus dados não forem voláteis, o particionamento pode ajudar a reduzir as necessidades de manutenção e, se combinado com a compactação de tabela , você também poderá reduzir seu espaço de armazenamento geral. A resposta anterior de Alberto Murillo faz alusão à utilização do particionamento horizontal com base em uma região de dados, e essa abordagem pode ajudar a criar algumas janelas de manutenção para você, pois seus dados seriam mais específicos por região, em vez de globais.

A transição para uma tabela particionada não será fácil com a sua ausência atual de janelas de manutenção, mas você poderá utilizar uma abordagem descrita por Maria Zakourdaev que usa Visualizações Particionadas na parte superior da tabela atual e uma nova tabela particionada para iniciar o particionamento. dados futuros. À medida que o tempo passa (e esperamos que seus dados antigos sejam eliminados), você pode eventualmente fazer a transição completa para a tabela particionada. Novamente, não conheço seus dados ou aplicativo, mas talvez essa abordagem seja algo que você possa empregar.

John Eisbrener
fonte
4

Primeiro, é importante considerar se a fragmentação é importante.

Se sua consulta estiver apenas fazendo buscas em linha única, talvez você não note fragmentação. Nas SANs modernas, o cache no nível da SAN pode fazer com que as IO phyiscal sejam rápidas o suficiente para que a fragmentação não importe. No SSD, o padrão aleatório de E / S causado pela varredura de um índice fragmentado pode realmente resultar em melhor desempenho que os dados não fragmentados.

Muitas vezes, as pessoas percebem que a reconstrução de um índice corrigia um problema de desempenho. A reconstrução de um índice também cria novas estatísticas. Pode ser que a correção real seja uma nova estatística, não reconstruindo o índice. UPDATE STATISTICS...WITH FULLSCANpode ser uma maneira mais barata, rápida e menos invasiva de resolver o mesmo problema de desempenho.

Se você não está tendo problemas causados ​​pela fragmentação, pode estar gastando tempo e esforço significativos sem obter ganhos reais.

Segundo, existem dois tipos de fragmentação:

  1. Fragmentação física. É nisso que a maioria das pessoas pensa quando pensa em fragmentação. As páginas estão com defeito e precisam ser reordenadas. Ao digitalizar um índice, esse tipo de fragmentação pode às vezes ser um problema. Eu geralmente notei que isso tem o maior impacto no desempenho com leituras físicas . Se você estiver vendo os resultados sys.dm_db_index_physical_stats, esse número é a avg_fragmentation_in_percentcoluna.

  2. Fragmentação de baixa densidade. Essa fragmentação é causada por páginas preenchidas apenas parcialmente com dados. Você tem baixa densidade de dados porque seus dados estão espalhados por mais páginas do que o necessário. Como resultado, a leitura dos dados requer mais pedidos de veiculação porque os dados estão espalhados por mais páginas do que o necessário. Isso pode afetar as leituras lógicas e físicas. Se você estiver vendo os resultados sys.dm_db_index_physical_stats, esse número é a avg_page_space_used_in_percentcoluna. Esta coluna é preenchida apenas ao usar o modo SAMPLEDou DETAILED.

Então o que fazer sobre isso:

Fragmentação física : se você está simplesmente buscando números altos avg_fragmentation_in_percent, considere realmente se está desperdiçando seu tempo. Verifique se você possui uma consulta real com desempenho ruim e use um ambiente de teste para confirmar que está corrigindo um problema eliminando a fragmentação.

Você pode resolver a fragmentação física fazendo ALTER INDEX...REORGANIZE. A REORGANIZEoperação está online, movendo as páginas uma por vez para reorganizá-las novamente em ordem física. Se você interromper uma REORGANIZEinstrução no meio do processo, qualquer trabalho que já tenha sido executado será mantido - apenas a página que está sendo movida no momento será revertida. Fazer uma REORGANIZEtabela grande e altamente fragmentada pode exigir mais espaço total no log de transações e, no modo de recuperação total, pode gerar uma quantidade significativa de backups do log de transações. Também pode levar mais tempo para REORGANIZEum índice altamente fragmentado do que para REBUILDele.

Você verá conselhos para executar REBUILDíndices altamente fragmentados em vez de REORGANIZE- Isso ocorre porque a reconstrução do zero pode ser mais eficiente. No entanto, a reorganização pode ser uma operação "mais on-line" e, às vezes, é preferível, mesmo para índices altamente fragmentados.

A fragmentação de baixa densidade não pode ser corrigida por REORGANIZE. Só pode ser corrigido fazendo um ALTER INDEX...REBUILD. Fazendo o índice com ONLINE=ON, você deve minimizar o bloqueio. No entanto, REBUILDainda é necessário bloquear por um momento para trocar o índice antigo pelo novo índice. Em um sistema muito ocupado, atingir esse bloqueio exclusivo pode às vezes ser um problema. Você deve poder confirmar se está tendo esse problema usando algo como sp_whoisactive para examinar o bloqueio durante sua reconstrução e observando os detalhes dos bloqueios e esperas. O uso da WAIT_AT_LOW_PRIORITYopção pode ser útil se você souber que há um próximo período de baixa utilização e sua reconstrução pode "se infiltrar" nessa troca quando a atividade cair suficientemente baixa para atingir esse bloqueio. Observe que uma longa duraçãoREBUILDA operação também será uma transação aberta de longa duração. As transações abertas de longa execução podem ter seus próprios problemas, relacionados ao uso / reutilização do log de transações. Se você estiver usando o espelhamento ou os Grupos de disponibilidade, também haverá considerações para refazer o log de transações na réplica secundária.

AMtwo
fonte
A fragmentação de baixa densidade (também conhecida como "fragmentação interna") é geralmente corrigida por a REORGANIZE. No BOL : "A reorganização também compacta as páginas de índice". Bem, desde que o FILLFACTOR atual do índice permita a densidade que você procura.
Granger
2

Aviso prévio

Após este comentário:

Você perderá linhas que são inseridas durante a cópia. Se você deseja evitar isso bloqueando a tabela, você acaba com o mesmo problema que o OP indicado em sua pergunta. Também 200Gb não virá de graça :-) - Marco 5/09 '17 às 11:18

... Vejo como essa abordagem não funcionará.

Deixarei essa resposta como um exemplo do que não fazer.


Se você tiver mais de 200 GB livres disponíveis no banco de dados do Azure, poderá se infiltrar com a "reconstrução", copiando seus dados para uma tabela totalmente nova e solicitando-a lá.

Tentar:

  • script seu LiveTableem um vazioNewTable
  • copiando o LiveTablepara oNewTable
  • renomeando LiveTableparaOldTable
  • renomeando NewTableparaLiveTable

Obviamente, use o nome da sua tabela em vez de LiveTable.

Oreo
fonte
Oreo, eu usaria a mesma abordagem que você. Mesmo quando houver linhas inseridas durante a cópia, você ainda poderá adicioná-las depois que a NewTable for renomeada para LiveTable. O principal problema que você evita aqui é o tempo de inatividade prolongado. Você pode até bcp-lo (copiar para E / S). Não é uma má idéia, então eu não entendo a downvote quer :-)
Koen D
1

Idealmente, se um índice for bem projetado, não precisaremos mexer no mecanismo de bloqueio.

Parece-me que você precisará aceitar o bloqueio para desfragmentar o índice em cluster. Se houver uma boa chance de isso acontecer novamente, tente redesenhar o índice em cluster (ele deve ser estreito, exclusivo, estático e sempre crescente).

Não tenho certeza de qual versão do SQL Server você está usando, mas tente o seguinte em 2012:

  • SET DEADLOCK_PRIORITY LOW - Isso informa ao mecanismo que a reconstrução do índice deve ser a vítima do impasse quando / se ocorrer um.

  • MaxDOP = 1 - O valor MaxDOP limita o número total de CPUs lógicas usadas em paralelo para criar o índice (2005 em diante - somente na edição Enterprise).

Você também pode alterar a configuração de bloqueios de página / linha, mas eu não faria isso sem testar. Você pode apenas piorar o bloqueio, especialmente se for um índice mal projetado.

A partir de 2014, existe a seguinte opção que basicamente diz ao mecanismo para permitir que outras sessões prossigam e a operação de índice online aguarde:

(WAIT_AT_LOW_PRIORITY (MAX_DURATION = 1 MINUTES, ABORT_AFTER_WAIT = SELF))
GPep
fonte
0

Eu usei a mesma abordagem que o Oreo descrita acima com grande sucesso! A única coisa que falta é que você precisa executar um script de atualização depois de copiar os dados e fazer a última renomeação.

A atualização ficará assim:

Insert from OldTable into LiveTable
  Where not exists (select From OldTable Where LiveTable.Key = OldTable.Key)

Se Key for uma coluna Identity, você precisará usar uma abordagem ligeiramente diferente.

SBB
fonte
Como observado sob a resposta de Oreo, seu método não vai funcionar se houver dados ainda estão sendo adicionados à tabela original, a menos que você bloquear a tabela original, que derrota o propósito do exercício
Tom V - tentativa topanswers.xyz
-2

Tente usar o sharding para distribuir dados geograficamente do seu banco de dados. Você poderá identificar diferentes janelas de manutenção para cada localização geográfica, e o tempo para fazer a manutenção será menor. Isso também irá melhorar o desempenho. Você pode aprender mais sobre este artigo. Não espere o banco de dados aumentar.

Com grandes bancos de dados e usuários conectados 24 x 7, é necessário usar a reorganização do índice e atualizar apenas as estatísticas que precisam ser atualizadas (sp_updatestats) para minimizar o tempo necessário para a manutenção e o impacto para os usuários.

Espero que isto ajude.

Alberto Morillo
fonte