Precisamos criar o valor de hash dos dados nvarchar para fins de comparação. Existem vários algoritmos de hash disponíveis no T-SQL, mas qual é o melhor para escolher neste cenário?
Queremos garantir que o risco de ter um valor de hash duplicado para dois valores nvarchar diferentes seja o mínimo. Com base em minha pesquisa na internet, o MD5 parece o melhor. Isso está certo? O MSDN nos informa (link abaixo) sobre os algoritmos disponíveis, mas nenhuma descrição sobre qual deles para quais condições?
Precisamos unir duas tabelas em duas colunas nvarchar(max). Como você pode imaginar, a consulta leva muito tempo para ser executada. Achamos que seria melhor manter o valor de hash de cada dado nvarchar(max) e fazer a junção nos valores de hash em vez dos valores nvarchar(max) que são blobs. A questão é qual algoritmo de hash fornece a exclusividade, para que não corramos o risco de ter um valor de hash para mais de um nvarchar(max).
A
HASHBYTES
função leva apenas até 8000 bytes como entrada. Como suas entradas são potencialmente maiores do que isso, duplicatas no intervalo do campo que recebe hash causarão colisões, independentemente do algoritmo escolhido. Considere cuidadosamente o intervalo de dados que você planeja fazer hash - usar os primeiros 4.000 caracteres é a escolha óbvia , mas pode não ser a melhor escolha para seus dados.De qualquer forma, por causa do que é uma função hash, mesmo que as entradas tenham 8.000 bytes ou menos, a única maneira de garantir 100% de exatidão nos resultados é comparar os valores básicos em algum ponto (leia-se: não necessariamente primeiro ). Período.
A empresa ditará se 100% de precisão é necessária ou não. Isso lhe dirá que (a) é necessário comparar os valores básicos ou (b) você deve considerar não comparar os valores básicos -- quanta precisão deve ser trocada pelo desempenho.
Embora as colisões de hash sejam possíveis em um único conjunto de entrada, elas são infinitamente raras, independentemente do algoritmo escolhido. A ideia de usar um valor de hash neste cenário é restringir com eficiência os resultados da junção a um conjunto mais gerenciável, não necessariamente chegar ao conjunto final de resultados imediatamente. Novamente, para 100% de precisão, esta não pode ser a etapa final do processo. Este cenário não está usando hash para fins de criptografia, portanto, um algoritmo como o MD5 funcionará bem.
Seria extremamente difícil para mim justificar a mudança para um algoritmo SHA-x para fins de "precisão", porque se a empresa vai surtar com as minúsculas possibilidades de colisão do MD5, é provável que eles também surtem com isso os algoritmos SHA-x também não são perfeitos. Eles precisam aceitar a pequena imprecisão ou exigir que a consulta seja 100% precisa e viva com as implicações técnicas associadas. Suponho que se o CEO dormir melhor à noite sabendo que você usou SHA-x em vez de MD5, tudo bem; ainda não significa muito do ponto de vista técnico neste caso.
Por falar em desempenho, se as tabelas forem principalmente lidas e o resultado da junção for necessário com frequência, considere a implementação de uma exibição indexada para eliminar a necessidade de calcular toda a junção toda vez que ela for solicitada. É claro que você troca o armazenamento por isso, mas pode valer a pena para melhorar o desempenho, especialmente se 100% de precisão for necessária.
Para ler mais sobre a indexação de valores de string longa, publiquei um artigo que mostra um exemplo de como fazer isso para uma única tabela e apresenta coisas a serem consideradas ao tentar o cenário completo nesta questão.
MD5 deve estar bem e a saída pode ser armazenada em um binário (16). A probabilidade de uma colisão (ver paradoxo do aniversário ) ainda é muito baixa, mesmo com um grande tamanho de amostra física. A saída de SHA-1 leva 20 bytes e a saída de SHA-256 leva 32 bytes. A menos que você tenha um número tão grande de registros que sua probabilidade de colisão de aniversário se torne significativa (fisicamente impossível ou pelo menos impraticável com as tecnologias de hardware atuais), provavelmente estará tudo bem.
Eu iria com SHA-1, é o melhor dos algoritmos disponíveis e tem a menor expectativa de colisão de todos eles (2 ^ 51 em comparação com MD5, que é 2 ^ 20,96). O MD5 também provou ser vulnerável a colisões em determinados cenários.
Fontes:
http://en.wikipedia.org/wiki/SHA-1 http://en.wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions#Cryptanalysis http://en.wikipedia.org/wiki/MD5
Eu não vi isso mencionado nas respostas, mas por MSDN :
Eu fiz uma pergunta semelhante, então cabe a você decidir se deseja usar uma função obsoleta, como MD5 (se estiver no 2016+). Você pode fazer testes para ver quanta diferença existe em armazenamento e desempenho entre MD5 e SHA2.