Eu tenho uma tabela modificada em série de eventos processados. Um horário utc para quando foi processado e um eventId.
É seguro usar SYSUTCDATETIME() como minha chave primária? Posso facilmente usar uma chave substituta, mas achei engraçado.
Eu tenho uma tabela modificada em série de eventos processados. Um horário utc para quando foi processado e um eventId.
É seguro usar SYSUTCDATETIME() como minha chave primária? Posso facilmente usar uma chave substituta, mas achei engraçado.
(Observe que a redação original da pergunta era: "O SYSUTCDATETIME é um índice clusterizado seguro?")
O que exatamente você quer dizer com "seguro"? Um índice agrupado não precisa ser exclusivo, portanto, é "seguro" no sentido de que não quebrará nada. Mas não pode ser uma chave primária, pois não pode ser garantido que seja exclusivo. Apenas tente o seguinte e você verá que o valor retornado da função é o mesmo em todas as linhas:
E então a questão é: o que exatamente você ganharia usando
SYSUTCDATETIME()
em vez de umIDENTITY
? Eu suponho que você esteja usando umaDATETIME2
coluna, que é de 8 bytes, mas você provavelmente poderia se safar com 4 bytesINT
para aIDENTITY
coluna.Então, eu iria com uma
INT
via preenchidaIDENTITY
como está:ATUALIZAR
Não, eu pessoalmente não confiaria em um valor, mesmo com uma resolução tão alta como
DATETIME2
, para ser uma chave primária, pois ainda é possível que duas operações ocorram no mesmo microssegundo. E você não pode garantir que em nenhum momento no futuro alguém ou algum processo irá inserir mais de 1 registro em uma única instrução.ATUALIZAÇÃO 2
@ypercubeᵀᴹ traz um bom ponto em um comentário abaixo (um comentário que logo desaparecerá magicamente agora que o mencionei aqui ;-):
Sim, às vezes essa é uma boa opção, mas não deixa de ter consequências em potencial devido à(s) chave(s) do índice clusterizado sendo copiada(s) para índices não clusterizados:
Se houver apenas um índice não agrupado nesta tabela, o espaço ocupado pelo índice será basicamente o mesmo de qualquer maneira. Mas como as chaves do índice clusterizado precisam ser exclusivas (pelo menos internamente), pois são o RowID para os índices não clusterizados, para todas as linhas com
DATETIME2
valores duplicados, haverá aquele "uniquificador" extra de 4 bytes adicionado. E será adicionado duas vezes: uma vez ao Índice Clustered e uma vez ao Índice Non-Clustered para o IDENTITY PK.Se houver vários índices não agrupados, o impacto no espaço usado será:
(mínimo de 4 bytes + 4 bytes para qualquer valor de chave de índice clusterizado duplicado)
* number_of_indexes
* rows_in_table (menos se índices filtrados forem usados)
Esses números podem parecer pequenos para alguns, mas se estivermos trabalhando com centenas de milhões de linhas, eles se somam. E para aqueles que acreditam erroneamente que "o disco é barato", considere que a) o armazenamento corporativo não é barato e b) as operações de disco , como manutenção de índice, etc., também não são baratas (menos problema com o SSD, mas ainda assim). Para obter uma análise mais detalhada sobre os efeitos downstream das decisões de modelagem de dados, consulte o seguinte artigo que publiquei no SQL Server Central: O disco é barato! ORLY? (esse site requer registro gratuito para visualizar o conteúdo).
Isso não quer dizer "não faça isso", mas sim "faça apenas se o benefício superar o custo".
ATUALIZAÇÃO 3
Por uma questão de integridade, devo mencionar que um problema com o uso
DATETIME2
de valores na esperança de separar declarações individuaisINSERT
e/ouUPDATE
é que eles não são tão granulares quanto parecem ser. Esta é uma questão entre "resolução" e "precisão". A "precisão" deDATETIME2
é de 7 casas decimais. Mas isso não significa que o valor de tempo mais granular representado seja incrementado no próximo valor quando isso acontecer. É como comDATETIME
valores precisos em milissegundos, você nunca obterá um valor que não seja 0, 3 ou 7 na posição de milissegundos:Da mesma forma com
DATETIME2
os valores, há um momento em que uma chamada paraSYSUTCDATETIME()
é totalmente precisa. Mas como o valor não é atualizado no próximo microssegundo, o valor relatado permanecerá constante por um momento até a próxima atualização. É por isso que o teste simples que @Paul postou em um comentário na Questão obtém violações de PK, mesmo que as duasINSERT
instruções estejam sendo executadas com pelo menos 1 microssegundo de diferença.Consulte a seguinte resposta do Stack Overflow para obter mais detalhes, incluindo um link para um projeto em CodeProject.com que possui código que pode ser usado no SQLCLR para superar essa limitação:
SQL Server CLR Integration não está chamando o horário do sistema como esperado