2011-07-08 13 views
6

Estoy intentando escribir una función almacenada de MySQL para generar UUID v4 como se describe en la sección 4.4 del RFC 4122 (http://www.ietf.org/rfc/rfc4122.txt). Mi esfuerzo ingenuo inicial después de algunos ajustes es la siguiente:¿Cómo puedo acelerar mi función MySQL UUID v4 almacenada?

CREATE FUNCTION UUID_V4() 
RETURNS BINARY(16) 
READS SQL DATA 
BEGIN 
    SET @uuid = CONCAT(
     LPAD(HEX(FLOOR(RAND() * 4294967296)), 8, '0'), 
     LPAD(HEX(FLOOR(RAND() * 4294967296)), 8, '0'), 
     LPAD(HEX(FLOOR(RAND() * 4294967296)), 8, '0'), 
     LPAD(HEX(FLOOR(RAND() * 4294967296)), 8, '0') 
    ); 
    SET @uuid = CONCAT(
     SUBSTR(@uuid FROM 1 FOR 12), 
     '4', 
     SUBSTR(@uuid FROM 14 FOR 3), 
     SUBSTR('ab89' FROM FLOOR(1 + RAND() * 4) FOR 1), 
     SUBSTR(@uuid FROM 18) 
    ); 
    RETURN UNHEX(@uuid); 
END 

La función anterior es bastante lento: casi 100 veces más lento que el incorporado en UUID(), según la característica de MySQL BENCHMARK(). A menos que escriba un UDF usando la API C de MySQL, ¿hay alguna mejora que pueda hacer aquí para, digamos, eliminar un orden de magnitud de su tiempo de ejecución?

Si ya existe un UDFU UDF o un procedimiento almacenado ya existente, me alegraría saber de eso también.

+0

No sé la respuesta, pero ¿por qué quieres crear tu propia función en lugar de utilizar la ya mencionada UUID de MySQL() uno (no sé si MySQL es diferente de RFC 4122, por lo que si lo hace lo siento para preguntar)? –

+0

El 'UUID()' de MySQL no genera un uuid de acuerdo con RFC4122, y la forma en que lo genera interrumpe la replicación basada en sentencias. –

+2

Su función también rompería la replicación basada en declaraciones. Puede evitar eso configurando el formato del binlog en "MIXED" o "ROW" para que la reproducción del registro no invoque la función, sino que inserte los valores de fila reales que hacen que UUID() sea viable para su uso. Además, ¿qué garantía hay de que su función no genere UUID duplicados? El único factor aleatorio que tienes es 5 llamadas a RAND() (que es lo que lo hace lento en primer lugar). Escribiría un UDF para MySQL e implementarlo de esa manera en lugar de crear la solución a través de la función, que debería proporcionar un mejor rendimiento. –

Respuesta

9

No probé esto por la corrección o el rendimiento. Es solo la idea de hacer una sola concatenación en lugar de dos.

create function uuid_v4() 
returns binary(16) 
begin 
    set @h1 = lpad(hex(floor(rand() * 4294967296)), 8, '0'); 
    set @h2 = lpad(hex(floor(rand() * 4294967296)), 8, '0'); 
    set @h3 = lpad(hex(floor(rand() * 4294967296)), 8, '0'); 
    set @h4 = lpad(hex(floor(rand() * 4294967296)), 8, '0'); 

    set @uuid = concat(
     @h1, 
     substr(@h2 from 1 for 4), 
     '4', 
     substr(@h2 from 6), 
     substr('ab89' from floor(1 + rand() * 4) for 1), 
     substr(@h3 from 2), 
     @h4 
    ); 
    return unhex(@uuid); 
end 
; 

también ¿Por qué usan READS SQL DATA en su función?

+0

re 'LEE DATOS SQL': actualmente tengo que usar la replicación basada en declaraciones, y' DETERMINISTIC', 'NO SQL', o' READS SQL DATA' es necesario para no romperla. –

+0

Pero usted sabe que esta afirmación no es segura de replicar, ¿verdad? – TehShrike

Cuestiones relacionadas