Vou criar uma tabela com dois campos - ID
como BIGINT
e IPAddress
como ou varchar(45)
ou varbinary(16)
. A idéia é armazenar todos os endereços IP exclusivos e usar uma referência em ID
vez do real IP address
em outras tabelas.
Geralmente, eu vou criar um procedimento armazenado que está retornando o ID
dado IP address
ou (se o endereço não foi encontrado) insira o endereço e retorne o gerado ID
.
Espero ter muitos registros (não sei exatamente quantos), mas preciso que o procedimento armazenado acima seja executado o mais rápido possível. Então, eu estou querendo saber como armazenar o endereço IP real - no formato de texto ou bytes. Qual vai ser melhor?
Eu já escrevi SQL CLR
funções para transformar bytes de endereços IP em string e o inverso, portanto, a transformação não é um problema (trabalhando com ambos IPv4
e IPv6
).
Acho que preciso criar um índice para otimizar a pesquisa, mas não tenho certeza se devo incluir o IP address
campo no índice clusterizado ou criar um índice separado e com qual tipo a pesquisa será mais rápida?
IPv4
acho que eu converteria o endereçoINT
e usaria o campo como chave de índice. Mas, comoIPv6
preciso usar doisBIGINT
campos e prefiro armazenar o valor em um campo - me parece mais natural.Respostas:
Como "texto" aqui se refere
VARCHAR(45)
e "bytes" se refereVARBINARY(16)
, eu diria: nenhum .Dadas as seguintes informações (do artigo da Wikipedia sobre IPv6 ):
Eu começaria usando 8
VARBINARY(2)
campos para representar os 8 grupos. Os campos dos Grupos 5 a 8 devem serNULL
como eles serão usados apenas para endereços IPv6. Os campos dos Grupos 1 a 4 devem ser osNOT NULL
que serão usados para os endereços IPv4 e IPv6.Ao manter cada grupo independente (em vez de combiná-los em
VARCHAR(45)
umVARBINARY(16)
ou maisBIGINT
campos), você obtém dois benefícios principais:IF
/IIF
/CASE
declarações para facilitar este processo.ROW COMPRESSION
ouPAGE COMPRESSION
. Como os dois tipos de COMPRESSION permitirão campos que0x00
ocupam 0 bytes, todos esses grupos de zeros agora não custarão nada. Por outro lado, se você armazenasse o endereço de exemplo acima (na citação da Wikipedia), os três conjuntos de todos os zeros no meio ocupariam toda a sua quantidade de espaço (a menos que você estivesse fazendo o mesmoVARCHAR(45)
e seguisse a notação reduzida) , mas isso pode não funcionar bem para a indexação e exigiria uma análise especial para reconstruí-la para o formato completo, então vamos supor que essa não seja uma opção ;-)Se você precisar capturar a rede, crie um
TINYINT
campo para o chamado, hum,[Network]
:-)Para obter mais informações sobre o valor da rede, veja algumas informações de outro artigo da Wikipedia sobre o endereço IPv6 :
Para indexação, eu diria que criar um índice não clusterizado nos 8 campos do grupo e, possivelmente, o campo rede, se você decidir incluir isso.
O resultado final deve ser algo como o seguinte:
Notas:
BIGINT
o campo ID, mas você realmente espera capturar mais de 4.294.967.295 valores exclusivos? Nesse caso, basta alterar o campo para BIGINT e você pode até alterar o valor inicial para 0. Mas, caso contrário, é melhor usar INT e começar com o valor mínimo para poder usar todo o intervalo desse tipo de dados. .SELECT *
retorne os campos na ordem esperada. Mas o índice tem-los indo para cima , 1-8, como é assim que eles são preenchidos.Um exemplo (inacabado) de uma coluna computada para representar os valores em forma de texto é:
Teste:
Resultado:
fonte
VARDECIMAL
terminadasVARBINARY
já queDATA_COMPRESSION
não está disponível?BINARY(16)
;-). Você pode me dar um exemplo com um intervalo de início / fim e pelo menos duas linhas retornadas, uma válida e pelo menos uma inválida? Pode ser que o VARbinary reduz alguns valores.Menor sempre será mais rápido. Com valores menores, você pode ajustar mais deles em uma única página, portanto menos IO, árvores B potencialmente mais rasas etc.
Todas as outras coisas (sobrecarga de tradução, legibilidade, compatibilidade, carga da CPU, capacidade de indexação etc.) são iguais, é claro.
fonte