Quais são os cenários de uso válidos para tabelas HEAP?

31

Atualmente, estou fazendo algumas importações de dados em um sistema legado e descobri que esse sistema não usa um único índice clusterizado. Uma rápida pesquisa no Google me apresentou o conceito de tabelas HEAP e agora estou curioso em quais cenários de uso uma tabela HEAP deve ser preferida a uma tabela em cluster?

Tanto quanto eu entendi, uma tabela HEAP seria útil apenas para tabelas de auditoria e / ou onde as inserções acontecem com muito mais frequência do que as selecionadas. Isso economizaria espaço em disco e E / S de disco, pois não há índice em cluster a ser mantido e a fragmentação adicional não seria um problema devido às leituras muito raras.

marc.d
fonte
1
Você está falando sobre o SQL Server?
precisa saber é o seguinte
@a_horse_with_no_name sim, eu esqueci de mencionar que SRY
marc.d
As tabelas de heap são boas para tabelas com milhões de linhas que são muito afetadas pelos usuários. A desvantagem é que eles podem ocupar muito espaço porque os dados são fisicamente armazenados sem classificação. Além disso, você depende de seus índices para ser ajustado às suas consultas. Trabalhei em locais que não usavam índices de cluster por causa de problemas de desempenho. Provavelmente devido a más opções de índices em cluster, mas se você usar apenas tabelas de heap, não precisará se preocupar com isso. Uma solução melhor seria usar a edição corporativa do servidor sql e particionar horizontalmente a tabela grande. Mas se você não tiver o ent
Consulte também stackoverflow.com/questions/1341393/… .
Jon de Todos os Negócios

Respostas:

22

Os únicos usos válidos são para

  • tabelas de preparação usadas em processos de importação / exportação / ETL.
  • backup ad-hoc, temporário e de curto prazo de tabelas usando SELECT * INTO..

As tabelas de preparo geralmente são bastante simples e truncadas antes / após o uso.

Observe que um índice em cluster geralmente é pequeno em comparação com o tamanho dos dados: os dados são o nível mais baixo da estrutura do índice.

As tabelas de heap também têm problemas. Pelo menos estes:

Veja também

gbn
fonte
2
Normalmente, usa pilhas para duas coisas separadas. Tabelas de preparação e trabalho ETL que eu uso para armazenar dados temporariamente quando o conjunto é grande demais para que uma tabela temporária funcione efetivamente. Todos os quais são truncados na próxima carga.
Zane
Boa pergunta, a propósito.
Zane
1
Um pequeno ajuste - se você fizer um SELECT INTO para criar um backup rápido de uma pequena tabela antes de fazer uma alteração, um heap será criado por padrão. Eu diria que é um uso válido - mas isso é apenas uma escolha. Eu gostaria de me livrar dessa pilha assim que soubesse que meu trabalho estava terminado.
Brent Ozar
@BrentOzar: Concordo, eu faço isso o tempo todo. O espírito da minha resposta é "tabelas persistentes e de longo prazo", mas vou atualizar
gbn
9

Principais considerações

Vejo uma vantagem importante para heaps e outra para tabelas em cluster, além de uma terceira consideração que pode ser feita de qualquer maneira.

  • Uma pilha poupa uma camada de indireção. Os índices contêm IDs de linha, apontando diretamente (bem, não realmente, mas o mais diretamente possível) para um local do disco. Portanto, uma pesquisa de índice em relação a um heap deve custar aproximadamente metade de uma pesquisa de índice não em cluster em uma tabela em cluster.

  • Um índice agrupado é classificado, por si só, graças a um índice (quase) livre. Como o índice de cluster é refletido na ordem física dos dados, ele ocupa relativamente pouco espaço em cima dos dados reais, o que, é claro, é necessário armazenar de qualquer maneira. Como é ordenada fisicamente, uma varredura de intervalo nesse índice pode procurar o ponto inicial e depois seguir com eficiência até o ponto final.

  • Os índices nos montes fazem referência aos RIDs, que são 64 bits. Como mencionado, os índices não agrupados em uma tabela em cluster referenciam a chave de cluster, que pode ser menor (32 bits INT), igual (64 bits BIGINT) ou maior (48 bits DATETIME2()mais 32 bits INT, ou um GUID de 128 bits). Obviamente, uma referência mais ampla gera índices maiores e mais caros.

Requisitos de espaço

Com estas duas tabelas:

CREATE TABLE TmpClustered
(
ID1 INT NOT NULL,
ID2 INT NOT NULL
)
ALTER TABLE TmpClustered ADD CONSTRAINT PK_Tmp1 PRIMARY KEY CLUSTERED (ID1)
CREATE UNIQUE INDEX UQ_Tmp1 ON TmpClustered (ID2)

CREATE TABLE TmpNonClustered
(
ID1 INT NOT NULL,
ID2 INT NOT NULL
)
ALTER TABLE TmpNonClustered ADD CONSTRAINT PK_Tmp2 PRIMARY KEY NONCLUSTERED (ID1)
CREATE UNIQUE INDEX UQ_Tmp2 ON TmpNonClustered (ID2)

... cada um preenchido com 8,7 M de registros, o espaço necessário era de 150 MB para os dados de ambos; 120 MB para os índices da tabela em cluster, 310 MB para os índices da tabela em cluster. Isso reflete que o índice de cluster é mais estreito que um RID e que o índice de cluster é principalmente um "brinde". Sem os índices exclusivos ID2, o espaço de índice necessário cai para 155 MB para a tabela não agrupada em cluster (metade, como seria de esperar), mas apenas 150 KB para a PK agrupada - quase nada.

Portanto, um índice não agrupado de um campo de 32 bits em uma tabela agrupada com um índice de 32 bits (total de 64 bits, nominalmente) ocupava 120 MB, enquanto um índice de um campo de 32 bits em um heap com um de 64 bits O RID (total de 96 bits, nominalmente) ocupou 155 MB, um pouco menos do que o aumento de 50% que se esperaria ingenuamente de passar de chaves de 64 bits para 96 ​​bits, mas é claro que há uma sobrecarga que reduz a diferença efetiva de tamanho.

Preencher as duas tabelas e criar seus índices levou o mesmo tempo para cada tabela. Executando testes simples que envolvem varreduras ou buscas, não encontrei diferenças significativas de desempenho entre as tabelas, o que corresponde ao white paper da Microsoft que o gbn vinculou de maneira útil. O referido documento mostra uma diferença significativa para acesso altamente simultâneo; Não sei por que isso acontece, espero que alguém com mais experiência do que eu em sistemas OLTP de alto volume possa nos dizer.

A adição de ~ 40 bytes de dados aleatórios de comprimento variável não alterou apreciavelmente essa equivalência. A substituição de INTs por UUIDs amplos também não (cada tabela foi reduzida na mesma extensão). Sua milhagem pode variar, mas na maioria dos casos, se um índice está disponível é mais importante do que que tipo.

Bits e Peças

Fazer uma varredura de intervalo em um índice não clusterizado - porque a tabela é uma pilha ou o índice não é o índice clusterizado - envolve a varredura do índice e, em seguida, uma pesquisa na tabela para cada ocorrência. Isso pode ser muito caro, então às vezes é mais barato apenas digitalizar a tabela. Você pode contornar isso com um índice de cobertura, no entanto. Isso se aplica se você agrupou sua tabela ou não.

Como o @gbn apontou, não há uma maneira simples de compactar um monte. No entanto, se sua tabela aumentar gradualmente ao longo do tempo - um caso muito comum - haverá pouco desperdício, pois o espaço liberado pelas exclusões será preenchido por novos dados.

Várias das discussões de heap versus tabela em cluster que eu vi fazem um argumento curioso de que um heap sem índices é inferior a uma tabela em cluster, pois sempre exige uma varredura de tabela. Isso certamente é verdade, mas a comparação mais significativa é "tabela agrupada grande e bem indexada" versus "pilha grande e bem indexada". Se sua tabela é muito pequena ou você sempre fará varreduras de tabela, então não importa muito se você a agrupa ou não.

Como cada índice em uma tabela em cluster faz referência ao índice de cluster, eles são, na verdade, todos os índices de cobertura. Uma consulta que faça referência a uma coluna indexada e a (s) coluna (s) de cluster pode fazer uma varredura de índice sem nenhuma pesquisa de tabela. Isso geralmente não é valioso se o seu índice de clustering for uma chave sintética, mas se for uma chave comercial que você precisa recuperar de qualquer maneira, é um recurso interessante.

TL; DR

Sou um especialista em data warehouse, não um especialista em OLTP. Para tabelas de fatos, quase sempre uso um índice de cluster no campo que provavelmente precisará de varreduras de intervalo, geralmente um campo de data. Para tabelas de dimensões, agrupo no PK, para que seja pré-definido para junções de mesclagem com tabelas de fatos.

Existem vários motivos para usar índices de cluster, mas se nenhum desses motivos se aplicar, a sobrecarga poderá não valer a pena. Eu suspeito que há muitas "sempre fizemos dessa maneira" e "é apenas uma prática recomendada" por trás de pessoas que usam índices agrupados universalmente. Tente ambos com os seus dados e sua carga e ver o que funciona melhor.

Jon de todos os comércios
fonte
5

Eu acho que dizer "O único uso válido é para tabelas temporárias usadas nos processos de importação / exportação / ETL" é um pouco restritivo, para dizer o mínimo. Você precisa pegar o caso de uso esperado de um determinado sistema e escolher com base nos méritos de pilhas ou tabelas organizadas por índices (eu sei, um termo do Oracle, mas ele o descreve bem).

Nosso armazém carrega ~ 1,5 bilhão de linhas por dia e deve suportar gravações e processamento altamente simultâneos, além de leituras. O armazenamento relacional suporta um banco de dados OLAP e, portanto, as leituras tendem a ser principalmente varreduras de tabela. Os relatórios e feeds downstream gerados também geralmente não são seletivos o suficiente para que qualquer índice seja útil. O sistema suporta uma janela deslizante de dados e, assim que uma tabela é carregada, raramente a escrevemos novamente e dada a implementação bastante pobre de particionamento de tabela, exigindo bloqueios Sch-M para divisões, comutadores e mesclagens versus bloqueios Sch-S para leituras, etc. , o sistema precisou usar muitas tabelas, embora também tenhamos algumas tabelas particionadas. O uso de muitas tabelas facilita a segmentação dos dados e ciclos de limpeza, além de reduzir a contenção.

Dessa forma, a sobrecarga adicionada de uma tabela organizada por índice (tabela em cluster) em algumas colunas arbitrárias versus a capacidade de bcp em um heap, processar as partições OLAP, executar algumas consultas de varredura de tabela e, em seguida, 3 dias mais tarde, significa que simplesmente não vale a pena. Observe que, no nosso caso, os dados retornam de um cluster de grade grande, de modo que também não há pedidos para os dados; portanto, a inserção em uma tabela com um índice clusterizado pode apresentar outros problemas, como "pontos de acesso", divisões de páginas e similares.

Além disso, acho que o argumento sobre a dispersão de páginas é um pouco falso. Os índices agrupados também podem ter suas páginas espalhadas por todo o arquivo. Só que, após a re-indexação (supondo mais de 1000 páginas), isso pode ser melhor do que um monte, mas você também teve que re-indexar também.

Também é possível economizar espaço usando colunas esparsas e compactação, se isso for um problema. É verdade que, em alguns casos, a seleção em uma tabela com um índice clusterizado pode ser mais rápida, mas é necessário ponderar isso com os recursos necessários para carregá-lo e mantê-lo.

[Editar] Eu provavelmente deveria deixar claro que apenas nossas tabelas de fatos não particionadas são montadas. Tabelas particionadas e tabelas de dimensão têm índices agrupados para oferecer suporte a pesquisas eficientes etc. [Edit2] Corrigido 2,5 bilhões a 1,5 bilhão. Tut, esses dois números estão próximos um do outro. O que acontece ao digitar respostas em um telefone, eu acho ...

Phil Stephenson
fonte