O AUTO_INCREMENT pode ser usado com segurança em um ANTES do TRIGGER no MySQL
O método Postgres do Instagram de implementar IDs personalizados para Sharding é ótimo, mas eu preciso da implementação no MySQL.
Então, converti o método encontrado na parte inferior deste blog, aqui:http://instagram-engineering.tumblr.com/post/10853187575/sharding-ids-at-instagram
Versão do MySQL:
CREATE TRIGGER shard_insert BEFORE INSERT ON tablename
FOR EACH ROW BEGIN
DECLARE seq_id BIGINT;
DECLARE now_millis BIGINT;
DECLARE our_epoch BIGINT DEFAULT 1314220021721;
DECLARE shard_id INT DEFAULT 1;
SET now_millis = (SELECT UNIX_TIMESTAMP(NOW(3)) * 1000);
SET seq_id = (SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = "dbname" AND TABLE_NAME = "tablename");
SET NEW.id = (SELECT ((now_millis - our_epoch) << 23) | (shard_id << 10) | (SELECT MOD(seq_id, 1024)));
END
A tabela é mais ou menos assim:
CREATE TABLE tablename (
id BIGINT AUTO_INCREMENT,
...
)
Pergunta, questão:
Há um problema de simultaneidade aqui. Ao gerar 100 threads e executar inserções, estou recebendo valores de sequência duplicados, o que significa que dois gatilhos estão obtendo o mesmo valor de incremento automático. Como posso consertar isso?Tentei criar uma nova tabela, por exemplo "tablename_seq", com uma linha, um contador para armazenar meus próprios valores de incremento automático e, em seguida, fazer atualizações nessa tabela dentro do TRIGGER, mas o problema é que não consigo LOCK a tabela em um Procedimento Armazenado (gatilho), então tenho o exatamente o mesmo problema, não posso garantir que um contador seja único entre os gatilhos :(.
Estou perplexo e realmente gostaria de receber dicas!
Solução possível:
O MySQL 5.6 possui UUID_SHORT (), que gera valores incrementais únicos, que são garantidos como únicos. Na prática, ao chamar isso, parece que cada chamada aumenta o valor +1. Usando: SET seq_id = (SELECT UUID_SHORT ()); parece remover o problema de simultaneidade. O efeito colateral disso é que agora (aproximadamente) não mais que 1024 pastilhas podem acontecer por milissegundo em todo o sistema. Se houver mais, é possível que haja um erro DUPLICATE PRIMARY KEY. A boa notícia é que, nos benchmarks da minha máquina, recebo ~ 3.000 inserções / s com ou sem o gatilho que contém UUID_SHORT (), para que não pareça retardá-lo.