"thaBadDawg" oferece uma boa resposta. Há um encadeamento paralelo no estouro de pilha que discute o tópico. Eu adicionei alguns comentários aos tópicos que respondem ao link para recursos com mais detalhes. Aqui está o link da pergunta: stackoverflow.com/questions/547118/storing-mysql-guid-uuids - Espero que esse tópico se torne mais comum quando as pessoas começarem a considerar a AWS e o Aurora.
Zack Jannsen
Respostas:
104
Meu DBA me perguntou quando perguntei sobre a melhor maneira de armazenar GUIDs para meus objetos por que eu precisava armazenar 16 bytes quando eu poderia fazer a mesma coisa em 4 bytes com um Número Inteiro. Desde que ele colocou esse desafio para mim, pensei que agora era um bom momento para mencioná-lo. Dito isto ...
Você pode armazenar um guia como um binário CHAR (16) se desejar fazer o melhor uso possível do espaço de armazenamento.
Porque com 16 bytes, você pode gerar coisas em diferentes bancos de dados, em máquinas diferentes, em momentos diferentes, e ainda mesclar os dados em conjunto sem problemas :)
Billy ONeal
4
precisa de resposta, o que realmente é um binário de 16 caracteres? não char? não é binário? Eu não vejo esse tipo em nenhuma das ferramentas mysql GUI, nem em qualquer documentação no site mysql. @BillyONeal
nawfal
3
@nawfal: Char é o tipo de dados. BINARY é o especificador de tipo em relação ao tipo. O único efeito que ele tem é modificar a forma como o MySQL faz a intercalação. Consulte dev.mysql.com/doc/refman/5.0/en/charset-binary-op.html para obter mais detalhes. Obviamente, você pode apenas usar um tipo BINARY diretamente se a sua ferramenta de edição de banco de dados permitir. (Ferramentas mais velhos não sabem do tipo de dados binários, mas sei da bandeira coluna binária)
Billy ONeal
2
um CHAR e um campo BINARY são essencialmente os mesmos. Se você quiser levá-lo ao nível mais básico, um CHAR é um campo binário que espera um valor de 0 a 255 com a intenção de representar o referido valor com um valor mapeado de uma tabela de pesquisa (na maioria dos casos agora, UTF8). Um campo BINARY espera o mesmo tipo de valor sem qualquer intenção de representar os dados a partir de uma tabela de pesquisa. Eu usei o CHAR (16) nos dias 4.x porque naquela época o MySQL não era tão bom quanto é agora.
ThaBadDawg
15
Existem várias razões pelas quais um GUID é muito melhor que um incremento automático. Jeff Atwood lista estes . Para mim, a melhor vantagem do uso de um GUID é que meu aplicativo não precisará de uma ida e volta ao banco de dados para conhecer a chave de uma entidade: eu poderia preenchê-lo programaticamente, o que não seria possível se estivesse usando um campo de incremento automático. Isso me salvou de várias dores de cabeça: com o GUID, posso gerenciar a entidade da mesma maneira, independentemente da entidade já ter sido persistida ou de uma nova.
@AfshinMehrabani É simples, direto, legível por humanos. Não é necessário, é claro, mas se o armazenamento desses bytes extras não prejudicar, essa é a melhor solução.
user1717828
2
Armazenar os traços pode não ser uma boa ideia, pois causará mais sobrecarga. Se você deseja torná-lo legível por humanos, faça o aplicativo ler com os traços.
Lucca Ferri
@AfshinMehrabani outra consideração é analisá-lo no banco de dados. A maioria das implementações espera traços em um guia válido.
Ryan Gates
Você pode inserir os hífens ao buscar para converter um char (32) em char (36) facilmente. use o Insert FN do mySql.
joedotnot 25/01
33
Acrescentando à resposta de ThaBadDawg, use essas funções úteis (graças a um colega mais sábio) para obter uma sequência de 36 caracteres de comprimento e uma matriz de 16 bytes.
CHAR(16)é realmente um BINARY(16), escolha seu sabor preferido
Para seguir melhor o código, use o exemplo, conforme o GUID ordenado por dígitos abaixo. (Caracteres ilegais são usados para fins ilustrativos - cada um possui um caractere exclusivo.) As funções transformarão a ordem dos bytes para obter uma ordem de bits para um cluster de índice superior. O guia reordenado é mostrado abaixo do exemplo.
Para os curiosos, essas funções são superiores a apenas UNHEX (REPLACE (UUID (), '-', '')) porque organiza os bits em uma ordem que terá melhor desempenho em um índice clusterizado.
Slashterix
Isto é muito útil, mas eu sinto que poderia ser melhorado com uma fonte CHARe BINARYde equivalência ( os docs parecem implicar há diferenças importantes e uma explicação do desempenho do índice porque agrupado é melhor com bytes reordenadas.
Patrick M
Quando eu uso isso, meu guia é alterado. Tentei inseri-lo usando unhex (replace (string, '-', '')) e a função acima e quando os converto novamente usando os mesmos métodos, o guid selecionado não é aquele que foi inserido. O que está transformando o guia? Tudo o que fiz foi copiar o código de cima.
Vsdev 17/12/2015
@JonathanOliver Você poderia compartilhar o código da função BinaryToGuid ()?
Arun Avanathan
27
char (36) seria uma boa escolha. Também é possível usar a função UUID () do MySQL, que retorna um formato de texto de 36 caracteres (hexadecimal com hífens) que pode ser usado para recuperar esses IDs do banco de dados.
Quanto você se importa com tamanho / desempenho de armazenamento versus facilidade de desenvolvimento? Mais importante: você está gerando GUIDs suficientes ou buscando-os com frequência suficiente para que isso importe?
Se a resposta for "não", char(36)é mais do que suficiente e torna os GUIDs de armazenamento / busca simples. Caso contrário, binary(16)é razoável, mas você terá que se apoiar no MySQL e / ou na sua linguagem de programação preferida para converter a partir da representação usual de strings.
Se você hospeda o software (por exemplo, uma página da web, por exemplo) e não vende / instala no cliente, sempre pode começar com char (36) para facilitar o desenvolvimento no estágio inicial do software e mudar para um formato mais compacto formato à medida que o sistema cresce em uso e começa a precisar de otimização.
Xavi Montero
1
A maior desvantagem do caractere muito maior (36) é a quantidade de espaço que o índice ocupará. Se você possui um grande número de registros no banco de dados, está dobrando o tamanho do índice.
bpeikes
8
Binário (16) seria bom, melhor do que o uso de varchar (32).
A rotina GuidToBinary postada pelo KCD deve ser ajustada para levar em conta o layout de bit do registro de data e hora na string GUID. Se a string representa um UUID da versão 1, como aqueles retornados pela rotina mysql uuid (), os componentes de tempo são incorporados nas letras 1-G, excluindo o D.
12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
12345678= least significant 4 bytes of the timestamp in big endian order9ABC = middle 2 timestamp bytes in big endian
D =1to signify a version 1 UUID
EFG = most significant 12 bits of the timestamp in big endian
Ao converter para binário, a melhor ordem para indexação seria: EFG9ABC12345678D + o restante.
Você não deseja trocar 12345678 por 78563412 porque o big endian já produz a melhor ordem de bytes de índice binário. No entanto, você deseja que os bytes mais significativos sejam movidos na frente dos bytes inferiores. Portanto, o EFG vai primeiro, seguido pelos bits do meio e pelos inferiores. Gere uma dúzia de UUIDs com uuid () ao longo de um minuto e você deverá ver como essa ordem gera a classificação correta.
Os dois primeiros UUIDs foram gerados mais próximos no tempo. Eles variam apenas nos últimos 3 petiscos do primeiro bloco. Esses são os bits menos significativos do registro de data e hora, o que significa que queremos empurrá-los para a direita quando convertemos isso em uma matriz de bytes indexáveis. Como um exemplo contrário, o último ID é o mais atual, mas o algoritmo de troca do KCD o colocaria antes do 3º ID (3e antes de dc, últimos bytes do primeiro bloco).
*** observe que não divido a mordidela da versão dos 12 bits mais altos do carimbo de data e hora. Esta é a mordidela D do seu exemplo. Eu apenas jogo na frente. Portanto, minha sequência binária acaba sendo DEFG9ABC e assim por diante. Isso implica que todos os meus UUIDs indexados começam com a mesma mordidela. O artigo faz a mesma coisa.
Eu li esse artigo antes. Acho muito interessante, mas como devemos fazer uma consulta se quisermos filtrar por um ID que é binário? Acho que precisamos nos azarar novamente e depois aplicar os critérios. Isso é tão exigente? Por que armazenar binário (16) (com certeza é melhor que varchar (36)) em vez de bigint de 8 bytes?
fwiw, o UUIDv4 é completamente aleatório e não precisa de chunking.
Mahmoud Al-Qudsi
2
Eu sugeriria o uso das funções abaixo, pois as mencionadas por @ bigh_29 transformam meus guias em novos (por razões que não entendo). Além disso, estes são um pouco mais rápidos nos testes que fiz nas minhas mesas. https://gist.github.com/damienb/159151
se você tiver um valor char / varchar formatado como o GUID padrão, poderá simplesmente armazená-lo como BINARY (16) usando o CAST simples (MyString AS BINARY16), sem todas essas sequências impressionantes de CONCAT + SUBSTR.
Os campos BINARY (16) são comparados / classificados / indexados muito mais rapidamente que as strings e também ocupam duas vezes menos espaço no banco de dados
A execução desta consulta mostra que o CAST converte a string uuid em bytes ASCII: set @a = uuid (); selecione @a, hex (converter (@a AS BINARY (16))); Eu recebo 16f20d98-9760-11e4-b981-feb7b39d48d6: 3136663230643938 2D 39373630 2D 3131 (espaços adicionados para formatação). 0x31 = ASCII 1, 0x36 = ASCII 6. Chegamos até 0x2D, que é o hífen. Isso não é muito diferente do que apenas armazenar o guia como uma sequência, exceto que você trunca a sequência no 16º caractere, o que separa a parte do ID que é específico da máquina.
bigh_29
Sim, isso é simplesmente truncamento. select CAST("hello world, this is as long as uiid" AS BINARY(16));produzhello world, thi
Respostas:
Meu DBA me perguntou quando perguntei sobre a melhor maneira de armazenar GUIDs para meus objetos por que eu precisava armazenar 16 bytes quando eu poderia fazer a mesma coisa em 4 bytes com um Número Inteiro. Desde que ele colocou esse desafio para mim, pensei que agora era um bom momento para mencioná-lo. Dito isto ...
Você pode armazenar um guia como um binário CHAR (16) se desejar fazer o melhor uso possível do espaço de armazenamento.
fonte
Eu o armazenaria como um caractere (36).
fonte
-
s.Acrescentando à resposta de ThaBadDawg, use essas funções úteis (graças a um colega mais sábio) para obter uma sequência de 36 caracteres de comprimento e uma matriz de 16 bytes.
CHAR(16)
é realmente umBINARY(16)
, escolha seu sabor preferidoPara seguir melhor o código, use o exemplo, conforme o GUID ordenado por dígitos abaixo. (Caracteres ilegais são usados para fins ilustrativos - cada um possui um caractere exclusivo.) As funções transformarão a ordem dos bytes para obter uma ordem de bits para um cluster de índice superior. O guia reordenado é mostrado abaixo do exemplo.
Traços removidos:
fonte
GuidToBinary
($ guid char (36)) RETORNA binário (16) RETURN CONCAT (UNHEX (SUBSTRING ($ guid, 7, 2)), UNHEX (SUBSTRING ($ guid, 5, 2)), UNHEX (SUBSTRING ($ guid, 3, 2)), UNHEX (SUBSTRING ($ guid, 1, 2)), UNHEX (SUBSTRING ($ guid, 12, 2)), UNHEX (SUBSTRING ($ guid, 10, 2)), UNHEX (SUBSTRING ($ guid, 17, 2)), UNHEX (SUBSTRING ($ guid, 15, 2)), UNHEX (SUBSTRING ($ guid, 20, 4)), UNHEX (SUBSTRING ($ guid, 25, 12)));CHAR
eBINARY
de equivalência ( os docs parecem implicar há diferenças importantes e uma explicação do desempenho do índice porque agrupado é melhor com bytes reordenadas.char (36) seria uma boa escolha. Também é possível usar a função UUID () do MySQL, que retorna um formato de texto de 36 caracteres (hexadecimal com hífens) que pode ser usado para recuperar esses IDs do banco de dados.
fonte
"Melhor" depende do que você está otimizando.
Quanto você se importa com tamanho / desempenho de armazenamento versus facilidade de desenvolvimento? Mais importante: você está gerando GUIDs suficientes ou buscando-os com frequência suficiente para que isso importe?
Se a resposta for "não",
char(36)
é mais do que suficiente e torna os GUIDs de armazenamento / busca simples. Caso contrário,binary(16)
é razoável, mas você terá que se apoiar no MySQL e / ou na sua linguagem de programação preferida para converter a partir da representação usual de strings.fonte
Binário (16) seria bom, melhor do que o uso de varchar (32).
fonte
A rotina GuidToBinary postada pelo KCD deve ser ajustada para levar em conta o layout de bit do registro de data e hora na string GUID. Se a string representa um UUID da versão 1, como aqueles retornados pela rotina mysql uuid (), os componentes de tempo são incorporados nas letras 1-G, excluindo o D.
Ao converter para binário, a melhor ordem para indexação seria: EFG9ABC12345678D + o restante.
Você não deseja trocar 12345678 por 78563412 porque o big endian já produz a melhor ordem de bytes de índice binário. No entanto, você deseja que os bytes mais significativos sejam movidos na frente dos bytes inferiores. Portanto, o EFG vai primeiro, seguido pelos bits do meio e pelos inferiores. Gere uma dúzia de UUIDs com uuid () ao longo de um minuto e você deverá ver como essa ordem gera a classificação correta.
Os dois primeiros UUIDs foram gerados mais próximos no tempo. Eles variam apenas nos últimos 3 petiscos do primeiro bloco. Esses são os bits menos significativos do registro de data e hora, o que significa que queremos empurrá-los para a direita quando convertemos isso em uma matriz de bytes indexáveis. Como um exemplo contrário, o último ID é o mais atual, mas o algoritmo de troca do KCD o colocaria antes do 3º ID (3e antes de dc, últimos bytes do primeiro bloco).
A ordem correta para a indexação seria:
Consulte este artigo para obter informações de suporte: http://mysql.rjweb.org/doc.php/uuid
*** observe que não divido a mordidela da versão dos 12 bits mais altos do carimbo de data e hora. Esta é a mordidela D do seu exemplo. Eu apenas jogo na frente. Portanto, minha sequência binária acaba sendo DEFG9ABC e assim por diante. Isso implica que todos os meus UUIDs indexados começam com a mesma mordidela. O artigo faz a mesma coisa.
fonte
Para aqueles que apenas tropeçam nisso, agora existe uma alternativa muito melhor conforme a pesquisa da Percona.
Consiste em reorganizar os chunks UUID para obter uma indexação ideal e depois converter em binário para reduzir o armazenamento.
Leia o artigo completo aqui
fonte
Eu sugeriria o uso das funções abaixo, pois as mencionadas por @ bigh_29 transformam meus guias em novos (por razões que não entendo). Além disso, estes são um pouco mais rápidos nos testes que fiz nas minhas mesas. https://gist.github.com/damienb/159151
fonte
se você tiver um valor char / varchar formatado como o GUID padrão, poderá simplesmente armazená-lo como BINARY (16) usando o CAST simples (MyString AS BINARY16), sem todas essas sequências impressionantes de CONCAT + SUBSTR.
Os campos BINARY (16) são comparados / classificados / indexados muito mais rapidamente que as strings e também ocupam duas vezes menos espaço no banco de dados
fonte
select CAST("hello world, this is as long as uiid" AS BINARY(16));
produzhello world, thi