$sql_code = 'insert into table1 (id, text) values (uuid(),'some text');';
mysql_query($sql_code);
如何在插入记录后立即检索生成的uuid?
char(36)
更好。你不能这样做。唯一的解决方法是执行2个单独的查询:
SELECT UUID()
INSERT INTO table1 (id, text) VALUES ($uuid, 'text')
其中$uuid是在第一步中检索到的值。
CHAR(36)
在UTF-8编码下会变成3*36个字节长,再加上长度字节。因此,你最好的选择是(A)二进制类型、(B)ASCII CHAR
类型或者(C)VARCHAR
类型。 - TimoCHAR(36)
的大小取决于可能包含在其中的数据(由字符集定义),而不是您此时刚好要存储的数据。是的,对于 UUID() 来说,它并不需要如此大的空间。但是(如果使用 UTF-8),您随时可以将其中存储 36 个日语字符,这需要更多的空间,而该列已经保留了这种可能性的空间,无论您是否使用它。这是使用 UTF-8 CHAR
应谨慎的原因。 - Timo你可以通过SQL触发器完成所需的一切操作。以下SQL在tablename.table_id
上添加了一个触发器,以便在插入时自动创建主键UUID,然后将新创建的ID存储到SQL变量中以供稍后检索:
CREATE TRIGGER `tablename_newid`
AFTER INSERT ON `tablename`
FOR EACH ROW
BEGIN
IF ASCII(NEW.table_id) = 0 THEN
SET NEW.table_id = UNHEX(REPLACE(UUID(),'-',''));
END IF;
SET @last_uuid = NEW.table_id;
END
// insert row
$sql = "INSERT INTO table1(text) VALUES ('some text')";
mysql_query($sql);
// get last inserted UUID
$sql = "SELECT HEX(@last_uuid)";
$result = mysql_query($sql);
$row = mysql_fetch_row($result);
$id = $row[0];
// perform a query using said ID
mysql_query("SELECT FROM table1 WHERE id = 0x" . $id);
回复@ina的评论:
UUID并不是一个字符串,即使MySQL选择将其表示为字符串。它在原始形式下是二进制数据,那些破折号只是MySQL以友好的方式向您表示它。
最有效的UUID存储方法是将其创建为UNHEX(REPLACE(UUID(),'-''))
- 这将删除该格式并将其转换回二进制数据。这些函数将使原始插入变慢,但您对该键或列执行的所有后续比较都将在16字节的二进制字段上比36个字符的字符串快得多。
首先,字符数据需要解析和本地化。任何传入查询引擎的字符串通常会与数据库的字符集自动匹配,并且一些API(例如wordpress)甚至在查询之前对所有字符串数据运行CONVERT()
。二进制数据没有这种开销。其次,您的char(36)
实际上分配了36个字符,这意味着(如果您的数据库是UTF-8),每个字符的长度可能为3或4个字节,具体取决于您使用的MySQL版本。因此,char(36)
的大小范围可以从36个字节(如果完全由低ASCII字符组成)到144个字节(如果完全由高阶UTF8字符组成)。这比我们为二进制字段分配的16个字节要大得多。
UNHEX()
来完成,但更好的方法是在查询中将数据作为十六进制进行转义,并在前面加上0x
。这样做与读取字符串一样快速,并在转换为二进制后直接分配给相关的查询或单元格。非常快。
从数据中读取数据略慢一些 —— 必须对从查询中读出的所有二进制数据调用HEX()
才能以有用的格式获得它们,如果你的客户端 API 无法很好地处理二进制数据(尤其是 PHP 通常会确定二进制字符串 === null
并且如果未经过第一次调用bin2hex()
、base64_encode()
或类似操作就对它们进行操作,则会破坏它们)—— 但这种开销与字符排序一样小,更重要的是,它仅在实际选择的单元格上被调用,而不是在查询结果的所有涉及单元格上被调用。
当然,所有这些小的速度增益都非常微小,而其他领域的效果则略微降低。但当你把它们全部加起来时,binary
仍然是最好的选择,特别是在考虑到使用情况和一般的“读取 > 写入”原则时,它真的很出色。
这就是为什么binary(16)
比char(36)
更好的原因。BEFORE INSERT
触发器的一些评论更新了我的答案,请参见edit2注释(: - pospi其实很简单,你可以将它传递给MySQL,它会返回插入的ID。
set @id=UUID();
insert into <table>(<col1>,<col2>) values (@id,'another value');
select @id;
INSERT
触发器上UUID键的存在意味着负责生成行的节点在运行其事务时创建该键,并且当数据级联到复制表时,该键存在于提供给其他节点的数据中。 - pospi
LAST_INSERT_ID()
只能在唯一列上工作,因此我才问。 - Pekka