CAST与TO_CHAR语义不同,不可比性能:CAST是类型转换,不支持格式控制;TO_CHAR是格式化函数,用于可读性、国际化等场景,结果可控且稳定。
CAST 和 TO_CHAR 的语义完全不同,不能直接比“性能”
很多人一上来就问「cast 和 to_char 哪个快」,这个问题本身就有偏差。因为 cast 是类型强制转换(比如 varchar2 ←→ number),而 to_char 是格式化输出函数,核心职责是「把值按指定样式转成字符串」。它俩解决的问题不在同一层。
比如你写 CAST(sysdate AS VARCHAR2(20)),Oracle 实际上只是做内存层面的二进制到字符字节的粗略映射,不走 NLS 格式逻辑;而 TO_CHAR(sysdate, 'YYYY-MM-DD HH24:MI:SS') 会严格解析 format mask、查 NLS 设置、做时区适配、填充前导空格等——后者天然更重。
-
CAST(... AS VARCHAR2)不支持格式控制,结果依赖数据库默认日期/数字格式(可能不可控) -
TO_CHAR必须显式指定 format,否则对日期返回类似'28-APR-26'这种依赖NLS_DATE_FORMAT的值,跨环境极易出错 - 对纯数字,
CAST(123.456 AS VARCHAR2(10))返回'123.456';TO_CHAR(123.456)默认也返回'123.456',但加了'FM999.00'就能输出'123.46'——这是CAST完全做不到的
什么时候必须用 TO_CHAR 而不是 CAST
只要涉及可读性、一致性或国际化,就必须用 TO_CHAR:
- 导出报表或生成文件时需要固定格式(如
'2026-04-28 16:16:00'),CAST给不出这个 - 处理货币、千分位、负号位置(如
TO_CHAR(-12345.67, 'L99,999.99')) - 提取日期部件:用
TO_CHAR(sysdate, 'Q')拿季度,TO_CHAR(sysdate, 'D')拿星期几(1=周日),CAST无法做到 - 连接字符串时隐式触发类型转换(如
'Order ID: ' || order_id),Oracle 内部会调用TO_CHAR,此时若order_id是NUMBER,行为等价于TO_CHAR(order_id),而非CAST
CAST 的真实适用场景很窄
CAST 在 Oracle 中主要用在两类地方:
- SQL 标准兼容性需求:比如写跨数据库脚本,或对接某些 ORM 框架要求显式类型声明
- 类型对齐强制转换:例如
UNION两个子查询,一列是NUMBER,另一列是VARCHAR2,必须用CAST(col AS NUMBER)或CAST(col AS VARCHAR2(20))统一类型才能通过语法检查 - 注意:
CAST('123' AS NUMBER)和TO_NUMBER('123')功能重叠,但前者不支持 format mask,错误处理也更硬(直接报 ORA-01722),而后者可通过TO_NUMBER('123', '999')控制解析规则
想用 CAST 把日期变成「看起来像字符串」?可以,但结果不可控、不可读、不可移植。这不是它的设计目标。
简单实测:执行计划和实际耗时差异不大,但风险点不同
在简单 SELECT 中,CAST(sysdate AS VARCHAR2(20)) 和 TO_CHAR(sysdate) 的执行计划几乎一样,CPU 时间差不到 1 微秒。但问题不在这里:
-
CAST不校验输入:CAST('abc' AS NUMBER)直接报错;TO_NUMBER('abc')同样报错;但TO_CHAR对非法输入反而更宽容(如TO_CHAR(NULL)返回NULL字符串) -
CAST对DATE→VARCHAR2的结果受NLS_DATE_FORMAT影响,而TO_CHAR(date, '...')完全绕过该参数,这才是稳定性的关键 - 最常被忽略的一点:
CAST(sysdate AS VARCHAR2(10))若长度不够(比如只给 8 字节),Oracle 会静默截断,不报错也不警告;TO_CHAR则按 format mask 精确生成,长度可预期
真正要较真性能,应该关注 format mask 复杂度:用 'YYYY-MM-DD HH24:MI:SS' 比用 'FMDAY, DD MONTH YYYY'(带英文星期/月份名)慢一个数量级,因为后者要查 NLS 语言表。这和 CAST 无关。



















