GUIDs/UUIDs are very random.
Therefore, INSERTing into an index means jumping around a lot.
Once the index is too big to be cached, most INSERTs involve a disk hit.
Even on a beefy system, this limits you to a few hundred INSERTs per second.
MySQL's UUID function
This blog is mostly eliminated in MySQL 8.0 with the advent of the following functions: UUID_TO_BIN(str, swap_flag)
Why it is a Problem
A 'standard' GUID/UUID is composed of the time, machine identification
and some other stuff. The combination should be unique, even
without coordination between different computers
that could be generating UUIDs simultaneously.
The top part of the GUID/UUID is the bottom part of the current time. The top part is the primary part of what would be used for placing the value in an ordered list (INDEX). This cycles in about 7.16 minutes.
Some math... If the index is small enough to be cached in RAM, each insert into the index is CPU only, with the writes being delayed and batched. If the index is 20 times as big as can be cached, then 19 out of 20 inserts will be a cache miss. (This math applies to any "random" index.)
36 characters is bulky. If you are using that as a PRIMARY KEY in InnoDB
and you have secondary keys, remember that each secondary key has an implicit
copy of the PK, thereby making it bulky.
It is tempting to declare the UUID VARCHAR(36). And, since you probably are thinking globally, so you have CHARACTER SET utf8 (or utf8mb4). For utf8:
⚈ 2 - Overhead for VAR
⚈ 36 - chars
⚈ 3 (or 4) bytes per character for utf8 (or utf8mb4)
So, max length = 2+3*36 = 110 (or 146) bytes. For temp tables 108 (or 144) is actually used if a MEMORY table is used.
⚈ utf8 is unnecessary (ascii would do); but this is obviated by the next two steps
⚈ Toss dashes
Now it will fit in 16 bytes: BINARY(16)
Combining the Problems and Crafting a Solution
But first, a caveat. This solution only works for "Time based" / "Version 1" UUIDs
They are recognizable by the "1" at the beginning of the third clump.
The manual's sample: 6ccd780c-baba-1026-9564-0040f4311e29 . A more current value (after a few years): 49ea2de3-17a2-11e2-8346-001eecac3efa . Notice how the 3rd part has slowly changed over time? Let's data is rearranged, thus:
1026-baba-6ccd780c-9564-0040f4311e29 11e2-17a2-49ea2de3-8346-001eecac3efa 11e2-17ac-106762a5-8346-001eecac3efa -- after a few more minutes
DELIMITER // CREATE FUNCTION UuidToBin(_uuid BINARY(36)) RETURNS BINARY(16) LANGUAGE SQL DETERMINISTIC CONTAINS SQL SQL SECURITY INVOKER RETURN UNHEX(CONCAT( SUBSTR(_uuid, 15, 4), SUBSTR(_uuid, 10, 4), SUBSTR(_uuid, 1, 8), SUBSTR(_uuid, 20, 4), SUBSTR(_uuid, 25) )); CREATE FUNCTION UuidFromBin(_bin BINARY(16)) RETURNS BINARY(36) LANGUAGE SQL DETERMINISTIC CONTAINS SQL SQL SECURITY INVOKER RETURN LCASE(CONCAT_WS('-', HEX(SUBSTR(_bin, 5, 4)), HEX(SUBSTR(_bin, 3, 2)), HEX(SUBSTR(_bin, 1, 2)), HEX(SUBSTR(_bin, 9, 2)), HEX(SUBSTR(_bin, 11)) )); // DELIMITER ;
-- Letting MySQL create the UUID: INSERT INTO t (uuid, ...) VALUES (UuidToBin(UUID()), ...); -- Creating the UUID elsewhere: INSERT INTO t (uuid, ...) VALUES (UuidToBin(?), ...); -- Retrieving (point query using uuid): SELECT ... FROM t WHERE uuid = UuidToBin(?); -- Retrieving (other): SELECT UuidFromBin(uuid), ... FROM t ...;Do not flip the WHERE; this will be inefficent because it won't use INDEX(uuid):
WHERE UuidFromBin(uuid) = '1026-baba-6ccd780c-9564-0040f4311e29' -- NO