Em um sistema de produção no SQL Server todos os ids (principalmente PKs) em todas as tabelas são gerados automaticamente e sou informado que eles são únicos globalmente. Quero dizer, não há 2 ids iguais no banco de dados, mesmo que as tabelas sejam diferentes. Eu quero saber como isso pode ser feito? Se houver várias maneiras, liste todas. Obrigado.
relate perguntas
-
SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado
-
Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?
-
Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?
-
Quais são as principais causas de deadlocks e podem ser evitadas?
-
Como determinar se um Índice é necessário ou necessário
Antigamente tínhamos
ID
mesa. Coluna única, linha única com umint
valor. Cada transação primeiro atualizava essa tabela para obter um novo valor, que era usado onde quer que fosse necessário. Isso foi, é claro, uma grande fonte de erros de simultaneidade.Mais tarde, as sequências foram introduzidas. Uma única sequência usada em todo o banco de dados mostraria o comportamento que você descreve. Há um exemplo na documentação que ilustra isso:
Editei o exemplo para destacar esse uso.
Um resultado idêntico pode ser obtido gerando os números globalmente exclusivos no código do aplicativo, antes de serem passados para o banco de dados. Se eu implementar isso, imagino que seria como um método estático de alguma classe de utilitário compilada no executável (embora outras implementações sejam possíveis). Digamos que o aplicativo precise gravar os detalhes de um cliente no banco de dados. Como ele está empacotando o nome do cliente, endereço, número de telefone, etc., ele também gera um novo ID global. O ID é passado para a instrução INSERT (ou procedimento armazenado) como apenas outro valor de parâmetro.
Se os valores de ID são produzidos pela camada de arquitetura do aplicativo ou pela camada de banco de dados depende das considerações de design específicas. Se o aplicativo pode escalar horizontalmente, a coordenação entre instâncias se torna problemática. Depois que um aplicativo é reiniciado, o código deve descobrir o próximo valor a ser usado. O servidor de banco de dados tem esses recursos e outros já gravados nele.
O que eu definitivamente não faria é fazer com que o aplicativo chamasse o banco de dados apenas para o próximo ID e, em seguida, empacotasse isso com os dados de negócios em um INSERT. São muitas viagens de ida e volta para o banco de dados quando apenas uma é necessária.
Para valores de ID exclusivos na mesma tabela, presumo que você esteja ciente da
IDENTITY
opção comumente usada, geralmente usando um valor de 32 bits a partir de 1 (portanto, para definir um PK dessa maneira, algo comoID INT NOT NULL IDENTITY(1,1) PRIMARY KEY
). É claro que você pode usar um (BIGINT
) maior se a tabela precisar de mais de 2.147.483.647 linhas.O SQL Server tem a opção de definir sua própria sequência que pode ser compartilhada entre várias tabelas, potencialmente todas elas. Consulte https://learn.microsoft.com/en-us/sql/t-sql/statements/create-sequence-transact-sql para obter detalhes. Em seguida, você define cada coluna de ID como
ID INTEGER DEFAULT NEXT VALUE FOR The_sequence_You_Defined PRIMARY KEY
. Há algumas coisas para estar ciente aqui embora. Ao contrário deIDENTITY
você, você não está impedido de inserir nenhum valor antigo (que ainda não esteja presente), pois o valor da sequência é aplicado por padrão somente se um não for fornecido explicitamente, o que pode ser problemático. Além disso, o uso de uma sequência é um pouco mais lento e pode se tornar um gargalo, pois todas as tabelas dependem do mesmo objeto, embora esses dois problemas sejam apenas uma preocupação se o banco de dados vir muita atividade de inserção em um curto espaço de tempo.NEXT VALUE FOR The_sequence_You_Defined
pode ser usado em outro lugar também (ou sejaSET @someVariable = NEXT VALUE FOR The_sequence_You_Defined;
) o que significa que se você precisar que os IDs sejam gerados em outro lugar na lógica do seu aplicativo, você pode fazer isso dessa maneira (na verdade, eu vi isso usado mesmo para uma única identidade, não apenas compartilhando uma sequência entre vários objetos).Uma abordagem mais complicada poderia ser usar um
BIGINT
para cada coluna de identidade e iniciar cada uma em um múltiplo diferente de (por exemplo) 4.000.000.000. Isso funcionará em outros bancos de dados e evita o problema do gargalo, mas dobra o tamanho da sua chave e pode causar um pesadelo de manutenção se você definir acidentalmente duas tabelas com IDs começando no mesmo ponto. Você pode querer adicionar restrições de verificação para garantir que um valor de identidade definido dessa maneira não possa transbordar para o espaço numérico de outro valor, o que adiciona novamente alguma preocupação de desempenho.Se você não se importa com a chave maior, os UUIDs são úteis e têm a vantagem adicional de serem exclusivos entre bancos de dados (todos os bancos de dados, como o nome sugere) e não apenas entre tabelas em um banco de dados. Assim como em uma sequência, eles são aplicados com uma restrição padrão, ou seja,
ID UNIQUEIDENTIFIER NOT NULL PRIMARY KEY DEFAULT NEWID()
. No entanto, esses são valores de 128 bits, duas vezes o tamanhoBITINT
e quatro vezes o tamanho de um 32 bits "padrão"INTEGER
. Se você está preocupado com o potencial de fragmentação extra causada pela aleatoriedade dos UUIDs v4, você pode usarNEWSEQUENTIALID()
em vez doNEWID()
que ainda deve ser único o suficiente (a chance de uma colisão durante a vida útil desta galáxia é muito pequena).Antes de mais nada, devo mencionar que não trabalhei com SQL Server, portanto não posso apontar alguns recursos específicos.
Eu tenho dois conceitos de como isso pode ser feito em minha mente:
No mundo do SQL Server, você pode consultar isto: Documentação NEWID() - newid é compatível com RFC4122