Pergunta

Do que eu uso varchar (36) ou existem melhores maneiras de fazer isso?

Foi útil?

Solução

Meu DBA me perguntou quando eu perguntei sobre a melhor maneira de armazenar GUIDs para meus objetos por isso que eu necessários para armazenar 16 bytes quando eu poderia fazer a mesma coisa em 4 bytes com um número inteiro. Desde que ele colocou esse desafio lá fora para mim eu pensei que agora era um bom momento para mencioná-lo. Dito isto ...

Você pode armazenar um GUID como um CHAR (16) binário se você quiser tirar o máximo aproveitamento do espaço de armazenamento.

Outras dicas

Gostaria de armazená-lo como um char (36).

Somando-se a resposta por ThaBadDawg, usar essas funções úteis (graças a um colega mais sábio da mina) para começar a partir de 36 comprimento da corda de volta para um array de bytes de 16.

DELIMITER $$

CREATE FUNCTION `GuidToBinary`(
    $Data VARCHAR(36)
) RETURNS binary(16)
DETERMINISTIC
NO SQL
BEGIN
    DECLARE $Result BINARY(16) DEFAULT NULL;
    IF $Data IS NOT NULL THEN
        SET $Data = REPLACE($Data,'-','');
        SET $Result =
            CONCAT( UNHEX(SUBSTRING($Data,7,2)), UNHEX(SUBSTRING($Data,5,2)),
                    UNHEX(SUBSTRING($Data,3,2)), UNHEX(SUBSTRING($Data,1,2)),
                    UNHEX(SUBSTRING($Data,11,2)),UNHEX(SUBSTRING($Data,9,2)),
                    UNHEX(SUBSTRING($Data,15,2)),UNHEX(SUBSTRING($Data,13,2)),
                    UNHEX(SUBSTRING($Data,17,16)));
    END IF;
    RETURN $Result;
END

$$

CREATE FUNCTION `ToGuid`(
    $Data BINARY(16)
) RETURNS char(36) CHARSET utf8
DETERMINISTIC
NO SQL
BEGIN
    DECLARE $Result CHAR(36) DEFAULT NULL;
    IF $Data IS NOT NULL THEN
        SET $Result =
            CONCAT(
                HEX(SUBSTRING($Data,4,1)), HEX(SUBSTRING($Data,3,1)),
                HEX(SUBSTRING($Data,2,1)), HEX(SUBSTRING($Data,1,1)), '-', 
                HEX(SUBSTRING($Data,6,1)), HEX(SUBSTRING($Data,5,1)), '-',
                HEX(SUBSTRING($Data,8,1)), HEX(SUBSTRING($Data,7,1)), '-',
                HEX(SUBSTRING($Data,9,2)), '-', HEX(SUBSTRING($Data,11,6)));
    END IF;
    RETURN $Result;
END
$$

CHAR(16) é realmente um BINARY(16), escolher o seu sabor preferido

Para seguir o código melhor, pegar o exemplo dado o GUID ordenou dígitos abaixo. (Caracteres ilegais são utilizados para fins ilustrativos - cada lugar um carácter único.) As funções irá transformar a ordenação byte para alcançar uma ordem de bits para o agrupamento índice superior. O guid reordenada é mostrado abaixo no exemplo.

12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
78563412-BC9A-FGDE-HIJK-LMNOPQRSTUVW

Os traços removidos:

123456789ABCDEFGHIJKLMNOPQRSTUVW
78563412BC9AFGDEHIJKLMNOPQRSTUVW

char (36) seria uma boa escolha. Também UUID do MySQL () função pode ser usada que retorna um formato de texto de 36 caracteres (hex com hífens) que pode ser usado para recuperações de tais IDs do banco de dados.

"Better" depende do que você está otimizando para.

Quanto você se preocupa com tamanho de armazenamento / performance vs. facilidade de desenvolvimento? Mais importante - você está gerando GUIDs suficientes, ou buscá-los com freqüência suficiente, que importa ?

Se a resposta for "não", char(36) é mais do que suficiente, e faz armazenar / buscar GUIDs mortos-simples. Caso contrário, binary(16) é razoável, mas você vai ter que se apoiar em MySQL e / ou sua linguagem de programação de escolha para converter e para trás a partir da representação habitual string.

Binary (16) seria bom, melhor do que o uso de varchar (32).

A rotina GuidToBinary postado por KCD deve ser ajustado para levar em conta o layout do timestamp na string GUID bit. Se a string representa uma versão 1 UUID, como aqueles retornados pela rotina mysql uuid (), em seguida, os componentes de tempo estão embutidos em letras 1-G, excluindo o D.

12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
12345678 = least significant 4 bytes of the timestamp in big endian order
9ABC     = middle 2 timestamp bytes in big endian
D        = 1 to signify a version 1 UUID
EFG      = most significant 12 bits of the timestamp in big endian

Quando você converter para binário, a melhor ordem para a indexação seria:. EFG9ABC12345678D + o resto

Você não quer trocar 12345678 a 78563412, porque big endian já produz a melhor ordem do índice byte binário. No entanto, você quer a maioria dos bytes significativos movidos na frente dos bytes inferiores. Assim, EFG ir primeiro, seguidos pelos bits do meio e pedaços menores. Gerar uma dúzia de UUIDs com uuid () ao longo de um minuto e você deve ver como esta ordem produz a classificação correta.

select uuid(), 0
union 
select uuid(), sleep(.001)
union 
select uuid(), sleep(.010)
union 
select uuid(), sleep(.100)
union 
select uuid(), sleep(1)
union 
select uuid(), sleep(10)
union
select uuid(), 0;

/* output */
6eec5eb6-9755-11e4-b981-feb7b39d48d6
6eec5f10-9755-11e4-b981-feb7b39d48d6
6eec8ddc-9755-11e4-b981-feb7b39d48d6
6eee30d0-9755-11e4-b981-feb7b39d48d6
6efda038-9755-11e4-b981-feb7b39d48d6
6f9641bf-9755-11e4-b981-feb7b39d48d6
758c3e3e-9755-11e4-b981-feb7b39d48d6 

Os dois primeiros UUIDs foram gerados mais próximo no tempo. Eles variam apenas nos últimos 3 petiscos do primeiro bloco. Estes são os bits menos significativos do timestamp, o que significa que queremos empurrá-los para a direita quando converter isso em um array de bytes indexável. Como um contra-exemplo, o último ID é o mais atual, mas algoritmo de troca da KCD iria colocá-lo antes da 3ª ID (3e antes dc, últimos bytes do primeiro bloco).

A ordem correta para a indexação seria:

1e497556eec5eb6... 
1e497556eec5f10... 
1e497556eec8ddc... 
1e497556eee30d0... 
1e497556efda038... 
1e497556f9641bf... 
1e49755758c3e3e... 

Consulte este artigo para informações de apoio: http://mysql.rjweb.org/doc.php / uuid

*** nota que eu não dividir a mordidela versão das altas de 12 bits do timestamp. Esta é a mordidela D a partir de seu exemplo. Eu simplesmente jogá-lo na frente. Então, minhas extremidades seqüência binária sendo DEFG9ABC e assim por diante. Isto implica que todos os meus UUIDs indexados começar com a mesma mordidela. O artigo faz a mesma coisa.

Para quem está tropeçando através deste, há agora é uma alternativa muito melhor conforme pesquisa realizada pela Percona.

Trata-se de uma reorganização dos pedaços UUID para indexação óptima, em seguida, a conversão em binário para armazenamento reduzido.

Leia o artigo completo aqui

Gostaria de sugerir usando as funções abaixo, desde os mencionados por @ bigh_29 transforma meus guids em novos (por razões que eu não entendo). Além disso, estes são um pouco mais rápido nos testes que fiz em minhas tabelas. https://gist.github.com/damienb/159151

DELIMITER |

CREATE FUNCTION uuid_from_bin(b BINARY(16))
RETURNS CHAR(36) DETERMINISTIC
BEGIN
  DECLARE hex CHAR(32);
  SET hex = HEX(b);
  RETURN LOWER(CONCAT(LEFT(hex, 8), '-', MID(hex, 9,4), '-', MID(hex, 13,4), '-', MID(hex, 17,4), '-', RIGHT(hex, 12)));
END
|

CREATE FUNCTION uuid_to_bin(s CHAR(36))
RETURNS BINARY(16) DETERMINISTIC
RETURN UNHEX(CONCAT(LEFT(s, 8), MID(s, 10, 4), MID(s, 15, 4), MID(s, 20, 4), RIGHT(s, 12)))
|

DELIMITER ;

Se você tem um valor de char / varchar formatado como o GUID padrão, você pode simplesmente armazená-lo como BINARY (16) usando o simples CAST (MyString AS BINARY16), sem todas essas sequências alucinantes de CONCAT + SUBSTR.

BINARY (16) campos são comparados / ordenada / indexado muito mais rápido do que cordas, e também tomar duas vezes menos espaço no banco de dados

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top