2011-07-08 56 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