Estou atrás de alguma confirmação dessa ideia para consertar um banco de dados com desempenho ruim ou uma sugestão melhor, se alguém tiver uma. Sempre aberto a melhores sugestões.
Eu tenho um banco de dados muito grande (mais de 20 milhões de registros crescendo cerca de 1/2 milhão por dia) que está usando GUID como PK.
Um descuido da minha parte, mas o PK está agrupado no servidor SQL e está causando problemas de desempenho.
O motivo de um guid - esse banco de dados é parcialmente sincronizado com 150 outros bancos de dados, portanto, o PK precisava ser exclusivo. A sincronização não é gerenciada pelo SQL Server, mas há um processo personalizado criado que mantém os dados sincronizados para os requisitos do sistema - tudo com base nesse GUID.
Cada um dos 150 bancos de dados remotos não armazena os dados completos armazenados no banco de dados SQL central. eles armazenam apenas um subconjunto dos dados de que realmente precisam, e os dados exigidos não são exclusivos deles (10 dos 150 bancos de dados podem ter alguns dos mesmos registros de bancos de dados de outros sites, por exemplo - eles compartilham). Além disso - os dados são realmente gerados nos sites remotos - não no ponto central - daí a necessidade dos GUIDs.
O banco de dados central é usado não apenas para manter tudo sincronizado, mas as consultas de mais de 3.000 usuários serão executadas nesse banco de dados fragmentado muito grande. Isso já é um grande problema nos testes iniciais.
Felizmente, ainda não estamos ativos - então posso fazer alterações e colocar as coisas offline, se necessário, o que é pelo menos alguma coisa.
O desempenho dos bancos de dados remotos não é um problema - os subconjuntos de dados são muito pequenos e o banco de dados geralmente nunca fica acima de 1 GB de tamanho total. Os registros são alimentados de volta ao sistema principal regularmente e removidos dos BDs menores quando não são mais necessários.
O desempenho do banco de dados central, que é o guardião de todos os registros, é lamentável - devido a um GUID agrupado como chave primária para tantos registros. A fragmentação do índice está fora dos gráficos.
Então - meus pensamentos para corrigir o problema de desempenho é criar uma nova coluna - Unsigned BIGINT IDENTITY (1,1) e, em seguida, alterar o Clustered PK da coluna BIGINT da tabela.
Eu criaria um índice exclusivo não clusterizado no campo GUID, que era a chave primária.
Os 150 bancos de dados remotos menores não precisam saber sobre o novo PK no banco de dados Central SQL Server - ele será usado exclusivamente para organizar os dados no banco de dados e interromper o mau desempenho e a fragmentação.
Isso funcionaria e melhoraria o desempenho do banco de dados SQL central e evitaria o futuro inferno da fragmentação do índice (até certo ponto, é claro)? ou eu perdi algo muito importante aqui que vai pular e me morder e causar ainda mais dor?
Você certamente NÃO precisa agrupar no GUID. Se você tiver algo que permita identificar exclusivamente registros diferentes desse GUID, sugiro que você procure criar um índice exclusivo nesse outro campo e tornar esse índice agrupado. Caso contrário, você está livre para agrupar em outros campos, mesmo usando índices não exclusivos. A abordagem que haveria para agrupar, no entanto, facilita a divisão de seus dados e a consulta - portanto, se você tiver um campo "região" ou algo assim, isso pode ser um candidato para seu esquema de agrupamento.
O problema com a mudança para um
BIGINT
seria adições aos dados de outros bancos de dados e integração de seu banco de dados no armazenamento central. Se isso não for uma consideração - e nunca será - então, sim,BIGINT
resolveria bem o problema de rebalanceamento do índice.Nos bastidores, se você não especificar um índice clusterizado, o SQL Server faz praticamente a mesma coisa: ele cria um campo de ID de linha e mapeia todos os outros índices para ele. Então, fazendo você mesmo, você está resolvendo da mesma forma que o SQL resolveria.
Isso é uma tarefa difícil.
Deixe-me sugerir uma abordagem intermediária.
Eu estava tendo problemas com System.Guid.NewGuid() gerando guids aleatórios. (Eu estava permitindo que o cliente criasse seu próprio guid, em vez de depender do banco de dados para criar um sequenceid).
Depois que mudei para um UuidCreateSequential no lado do cliente, meu desempenho ficou MUITO melhor, especialmente em INSERTs.
Aqui está o voodoo do código do cliente DotNet. Tenho certeza que penhorei de algum lugar:
IDEIA ALTERNATIVA:
Se o seu banco de dados principal e os bancos de dados remotos estiverem "vinculados" (como em sp_linkserver) ...... você poderá usar o banco de dados principal como o "gerador de uuid".
Você não quer obter "um por um" de uuid, isso é muita tagarelice.
Mas você pode pegar um conjunto de uuid's.
Abaixo segue algum código:
/*
*/
Com base na sua descrição, vá com BIGINT. No entanto, o índice para GUID pode ser não exclusivo, pois os GUIDs devem ser globalmente exclusivos de qualquer maneira.
Se o GUID for armazenado corretamente como identificador único, não haverá problemas de desempenho ... e se você puder usar o GUID sequencial ainda melhor ...
Também @mattytommo tem um bom ponto sobre 11,5 anos usando INT ...