O que acontece durante inserções "grandes" em uma tabela com uma chave composta em cluster?

8

Meu conhecimento de SQL é limitado, portanto os termos que usarei provavelmente não são os corretos.

Eu tenho uma tabela que irá armazenar os resultados dos testes, para vários locais.

Os testes serão gravados em diferentes bancos de dados em diferentes locais (sem conexão de rede) e o local "principal" importará regularmente os resultados dos outros locais.

Pretendo ter uma chave primária composta em cluster nas colunas LocationId (int) e Date (datetime), nessa ordem. O raciocínio é que ele deve manter todos os resultados de um local juntos e quase nunca faço uma consulta por período, mas sim por período e local.

O tamanho da linha será de 80 a 100 bytes e o número de resultados do teste não deve exceder alguns milhões. Uma "importação" típica inserirá de 50 a 100 mil resultados de outro local.

O que acontecerá durante as importações? O SQL "moverá" as linhas existentes para manter o clustering ou permitirá que a tabela fique "fragmentada"? Isso poderia causar um grande impacto no desempenho se a importação fosse feita uma linha por vez? Eu deveria preferir não me preocupar com a ordem das linhas e apenas adicionar uma coluna de identidade como chave primária e um índice na coluna Data para ajudar nas minhas consultas?

Sacha K
fonte

Respostas:

19

Caramba, você tem muitas perguntas aqui. Vamos quebrar isso.

P: O SQL "moverá" as linhas existentes para manter o clustering ou permitirá que a tabela fique "fragmentada"?

Pense em um banco de dados como uma coleção de páginas - literalmente pedaços de papel dispostos em sua mesa. Pense no dicionário por enquanto. Se você quiser adicionar mais palavras ao dicionário, poderá adicioná-las no lugar se as páginas tiverem espaço vazio.

Quando você começa com um dicionário vazio, isso é relativamente fácil. Mas pense em um dicionário maduro, com milhares de páginas em papel, todas cheias.

Quando você deseja adicionar mais palavras a esse dicionário maduro, é provável que não haja mais espaço na página. O SQL Server "rasgará" uma página - ela levará uma nova página para outro lugar e moverá algumas das palavras para a nova página. A nova página estaria no final do dicionário. A boa notícia é que, imediatamente após essa ação, agora existe uma página meio vazia no final do seu dicionário e também no meio, ambas com espaço para adicionar palavras.

Se você os adicionar nessa ordem, é isso. É por isso que a maneira como você carrega dados se torna cada vez mais importante.

Isso poderia causar um grande impacto no desempenho se a importação fosse feita uma linha por vez?

Esqueça o índice por um segundo - adicionar dados uma linha por vez é simplesmente ineficiente, independentemente da estrutura de indexação. O SQL Server é um sistema baseado em conjuntos - sempre que você puder trabalhar em conjuntos, provavelmente deverá.

O que acontece quando eu consulto os dados?

Você não perguntou isso, mas eu estou pedindo por você, hahaha.

Pense nas consequências de nossas inserções. Agora, temos um dicionário que é encomendado principalmente, mas quando você chegar a alguns pontos do dicionário, precisará pular para trás para ler algumas outras páginas. Se todas essas páginas estiverem armazenadas em cache em sua memória (RAM, buffer pool, etc.), a sobrecarga não será tão grande. De qualquer forma, o acesso à memória é aleatório - não é como o SQL Server armazena seu dicionário na memória em ordem.

Por outro lado, se você precisar buscar os dados dos discos rígidos magnéticos convencionais (ferrugem), poderá obter alguns benefícios de desempenho se esses dados forem armazenados em ordem. O objetivo real do projeto aqui, no entanto, é obter os dados da RAM em vez de obtê-los das unidades. A diferença entre dados desfragmentados no disco e dados fragmentados no disco não é tão significativa quanto a diferença entre obtê-lo do disco e obtê-lo da RAM .

Eu deveria preferir não me preocupar com a ordem das linhas e apenas adicionar uma coluna de identidade como chave primária e um índice na coluna Data para ajudar nas minhas consultas?

Bingo: esta é a diferença entre o design físico do banco de dados e o design lógico do banco de dados. Os programadores precisam se preocupar muito com o design físico do banco de dados inicialmente, mas desde que o seu banco de dados tenha menos de 100 GB de tamanho, é possível corrigir o design lógico na postagem, por assim dizer. Coloque um campo de identidade para iniciantes, agrupe-o e, depois de ficar ativo por alguns meses, revise o design do índice para maximizar o desempenho.

Agora, tendo dito isso, uma vez que você tenha experiência com esse tipo de tomada de decisão, estará melhor equipado para adivinhar os índices de estimativa desde o início. Mesmo assim, nem sempre penso muito no design de índice inicialmente. Os usuários nunca parecem consultar os dados da maneira que eu esperava.

Brent Ozar
fonte
11
A inserção de um por um era uma questão teórica. Pareceu-me duvidoso, em termos de desempenho, que "as linhas são armazenadas fisicamente no disco na mesma ordem que o índice de cluster" que você lê na maioria dos lugares.
Sacha K
Eu vou para uma coluna de identidade. Os dados serão adicionados "no final" e naturalmente classificados por data. As mesmas datas para diferentes locais não serão "próximas", mas isso não importa para mim.
Sacha K