MySQL在不丢失数据的情况下将CHAR(32)数据类型转换为BINARY(16)

时间:2019-03-29 12:39:16

标签: mysql

嗨,我有一个表,该表的列具有char(32)数据类型,我需要将其转换为BINARY(16)数据类型。我已经尝试过仅更改列类型,但这会删除列中的所有数据。

以下代码是我如何更新列的数据类型。这导致我丢失了该列中的所有数据。

ALTER TABLE table_name MODIFY device_uuid BINARY(16)

是否可以更改列的数据类型并将所有数据转换为新的数据类型而不会丢失任何数据。

之所以这样做,是因为我试图检索位于此表中的一些丢失的数据。我需要将数据导入到的表完全相同,但列类型为BINARY(16)而不是CHAR(32)

如果能帮助您,请提前感谢您。

2 个答案:

答案 0 :(得分:1)

听起来您想让UUID表示为十六进制数字的字符串。这些通常在其中包含四个破折号,因此长度实际上是36个字符。但是,如果删除破折号,则可以是32个字符。

mysql> SELECT UUID();
+--------------------------------------+
| UUID()                               |
+--------------------------------------+
| b4d841ec-5220-11e9-901f-a921a9eb9f5b |
+--------------------------------------+

mysql> SELECT REPLACE(UUID(), '-', '');
+----------------------------------+
| REPLACE(UUID(), '-', '')         |
+----------------------------------+
| d3dbd450522011e9901fa921a9eb9f5b |
+----------------------------------+

但是在十六进制字符串中,每两个字符表示可以编码为二进制数据的一个字节的数据。例如,FF是255的十六进制值,这是一个字节的最大值。因此,十六进制字符串占用的字节数是二进制等效数据的两倍。如果空间有限,则可能需要将UUID值转换为二进制值,以便将它们存储在一半的空间中。

您可以使用UNHEX() function进行此操作。

mysql> SELECT UNHEX(REPLACE(UUID(), '-', ''));
+---------------------------------+
| UNHEX(REPLACE(UUID(), '-', '')) |
+---------------------------------+
| $S,vR!??!??[                      |
+---------------------------------+

二进制数据在以人为本的界面中显示或键入时令人讨厌,因为某些字节对应于不可打印的字符。

但是,当您执行ALTER TABLE table_name MODIFY device_uuid BINARY(16)时,并没有使用UNHEX()来解码十六进制字符串。充其量,这会使ASCII十六进制字符的前16个字节映射到BINARY(16)列的16个字节,并且在那一刻截断了字符串。就像您对每一行都这样:

mysql> SELECT LEFT(REPLACE(UUID(), '-', ''), 16);
+------------------------------------+
| LEFT(REPLACE(UUID(), '-', ''), 16) |
+------------------------------------+
| 364e6db8522211e9                   |
+------------------------------------+

前16个字节仍然是十六进制数字。字节是这些数字的ASCII值,而不是每对数字的二进制等效值。每个字符串的后16个字节被截断,并且不存储。如果这些数据很重要,我希望您有数据库的备份,因为现在还原备份是恢复数据的唯一方法。

您应该做的是以下事情:

ALTER TABLE table_name ADD COLUMN device_uuid_bin BINARY(16);
UPDATE table_name SET device_uuid_bin = UNHEX(device_uuid);

...check the data to make sure the conversion worked... 
...test any applications work with the binary data... 

ALTER TABLE table_name DROP COLUMN device_uuid;

答案 1 :(得分:0)

如果采用Karwin给出的算法,并对位进行混洗,则会得到按时间顺序排列的UUID。由于半排序而不是“随机”,这通常对性能更好。

我在博客here中对此进行了讨论。它指出在MySQL 8.0的标准函数中已经提供了等效的代码。

此外,请注意,此“技巧”仅适用于MySQL / MariaDB使用的“类型1” uuid。