2011-07-08 22 views
6

我试图编写一个MySQL存储函数来生成v4 UUID,如RFC 4122第4.4节(http://www.ietf.org/rfc/rfc4122.txt)中所述。一些调整后,我最初的天真的努力如下:如何加快我的MySQL UUID v4存储功能?

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 

上述功能是相当缓慢:比内置UUID()慢近100倍,根据MySQL的BENCHMARK()功能。使用MySQL的C API编写UDF的缺点是,我可以做些什么改进,例如从运行时削减一个数量级?

如果有一个已经存在的,广受好评的UUID UDF或存储过程,我也很乐意听到这个消息。

+0

我不知道答案,但你怎么想创建自己的函数,而不是使用已经提到的MySQL的UUID()(我不知道MySQL的是否与RFC 4122不同,所以如果它确实感到抱歉问)? –

+0

根据RFC4122,MySQL的'UUID()'不会生成uuid,并且其生成方式会打破基于语句的复制。 –

+2

你的函数也会打破基于语句的复制。您可以通过将binlog格式设置为“MIXED”或“ROW”来避免这种情况,以便日志的重播不会调用该函数,而是插入使UUID()可供使用的实际行值。另外,有什么保证你的函数不会生成重复的UUID?你得到的唯一的随机因素是5个RAND()的调用(这首先使它变慢)。我会为MySQL编写一个UDF并以这种方式实现它,而不是通过函数创建解决方案,这应该会产生更好的性能。 –

回答

9

我没有测试它的正确性或性能。这只是一个连接而不是两个连接的想法。

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 
; 

此外,为什么你在你的功能使用READS SQL DATA

+0

re'READS SQL DATA':我目前不得不使用基于语句的复制,并且需要'DETERMINISTIC','NO SQL'或'READS SQL DATA'来不破坏它。 –

+0

但是你知道这个陈述是不安全的,对吗? – TehShrike