UNHEX()将偶数长度的十六进制字符串(如'414243')转换为对应二进制字节序列,奇数长度返回NULL;结果类型为VARBINARY,与字符串类型混用可能引发隐式转换和索引失效。

MySQL里UNHEX()到底把什么转成什么
UNHEX()只做一件事:把十六进制字符串(比如'414243')转成对应的二进制字节序列,不是转成文本,也不是转成数字。它不关心你传进来的是不是合法的十六进制——只要长度是偶数,就硬拆成字节;奇数长度直接返回NULL。
常见错误现象:UNHEX('ABC')返回NULL(长度为3,奇数);UNHEX('476F6F64')返回0x476F6F64,也就是字节序列0x47 0x6F 0x6F 0x64,在utf8mb4下查出来显示为'Good',但本质仍是二进制值。
- 必须确保输入是偶数长度的十六进制字符串,否则静默失败
- 如果原始数据来自前端或日志,可能带
'0x'前缀,得先用REPLACE(str, '0x', '')清理 - 结果类型是
VARBINARY,和CHAR/VARCHAR混用时可能触发隐式转换,导致比较失效(比如WHERE col = UNHEX('...')若col是VARCHAR,可能走不了索引)
什么时候该用HEX()而不是CONV()或CAST()
HEX()专用于把二进制值或字符串转成大写十六进制字符串,比如HEX('AB') → '4142',HEX(0x4142) → '4142'。它不处理数值进制转换——别拿它转十进制数255成'FF',那得用CONV(255,10,16)。
使用场景:导出二进制字段供调试、生成token摘要、和外部系统对接需要hex编码的字段。
-
HEX()对NULL输入返回NULL,不是空字符串 - 对中文等多字节字符,结果长度是UTF-8编码字节数的两倍(如
HEX('好')→'E5A5BD',因为'好'UTF-8占3字节) - 不要和
TO_BASE64()混淆——后者是base64编码,不是十六进制
HEX()和UNHEX()在WHERE条件里能走索引吗
不能直接走索引。因为HEX(col)是对列做函数运算,MySQL无法利用col上的索引;同理,UNHEX(?)) = col中若col是二进制类型,参数是hex字符串,实际执行的是“把参数转二进制再比”,优化器往往放弃索引。
真正能走索引的做法是:把查询条件也预转成二进制存起来,或者反向操作——比如想查UNHEX('414243')对应的数据,不如直接写WHERE col = 0x414243(前提是你知道原始hex值)。
- 如果字段是
BINARY或VARBINARY,且查询值已知hex形式,用0x414243字面量最高效 - 如果必须动态传hex字符串,考虑在应用层转成二进制再传参,避免SQL里调用
UNHEX() - 在WHERE里套
HEX(col) = '...'相当于全表扫描,大数据量时延迟明显
PostgreSQL或SQLite用户别直接抄MySQL写法
MySQL的HEX()/UNHEX()在其他数据库里不存在。PostgreSQL用encode(col, 'hex')和decode('414243', 'hex');SQLite用hex(col)和cast(x'414243' as blob)(注意x'...'是字面量语法,不是函数)。
容易踩的坑:把MySQL的UNHEX('4142')直接搬去PostgreSQL会报错function unhex(unknown) does not exist;或者误以为SQLite的hex()能逆向,其实它只有单向编码能力。
- 跨数据库迁移时,hex相关逻辑必须重写,没有兼容层
- PostgreSQL的
decode()要求输入严格小写,DECODE('4142', 'hex')会失败,得写DECODE('4142', 'hex')——等等,它其实不区分大小写,但文档没说清,实测大小写都行;重点是别漏掉第二个参数 - SQLite里
x'4142'是常量,不能写成x(col),也没unhex()函数










