Oracle(字符集分为服务端和客户端) 和 Hive(依赖 MySQL(或 PostgreSQL)存储元数据)字符集编码格式查询,中文乱码处理

Oracle与Hive中文乱码问题总结


核心问题:字符集不一致导致中文乱码。


Oracle处理

  1. 检查服务端字符集:SELECT * FROM nls_database_parameters WHERE parameter IN ('NLS_CHARACTERSET','NLS_NCHAR_CHARACTERSET');
  2. 统一客户端NLS_LANG设置,与服务端保持一致(如ZHS16GBK或AL32UTF8)

Hive处理

  1. 修改元数据库(Metastore)字符集为UTF-8:ALTER TABLE COLUMNS_V2 MODIFY COLUMN COMMENT VARCHAR(256) CHARACTER SET utf8;
  2. 检查数据文件编码:file -i 数据文件名
  3. 设置会话字符集:SET NAMES 'utf8';

最佳实践:新建表统一使用UTF-8编码,历史表通过ETL转码处理,避免直接修改生产表编码。银行数据迁移需特别注意源文件与目标系统编码一致性。


Oracle和Hive都是怎么查sql的字符集编码格式的,中文乱码怎么处理


在银行的数据迁移和日常查询中,中文乱码是绕不开的坎,根源通常是数据库字符集客户端/文件字符集不一致。


下面分别讲 Oracle 和 Hive 怎么查字符集、怎么处理乱码。


一、Oracle 字符集查看

Oracle 的字符集分为服务端客户端两个概念,乱码往往就是它俩不一致导致的。


1. 查询服务端数据库字符集

sql 复制代码
-- 方法1:查看NLS_CHARACTERSET参数(最常用)
SELECT * FROM nls_database_parameters 
WHERE parameter IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');

-- 方法2:获取完整的语言环境信息(包含客户端设置)
SELECT userenv('language') FROM dual;

结果示例

复制代码
NLS_CHARACTERSET = ZHS16GBK  或  AL32UTF8

ZHS16GBK 是简体中文字符集,AL32UTF8 是 Unicode 编码。

2. 查看客户端/当前会话字符集

sql 复制代码
-- 查看当前会话的字符集设置(即客户端NLS_LANG)
SELECT userenv('language') FROM dual;

二、Hive 字符集查看与元数据乱码解决

Hive 依赖 MySQL(或 PostgreSQL)存储元数据,中文乱码通常是 Hive 元数据库(Metastore)的字符集不是 UTF-8 造成的。


1. 查看 Hive 表注释/字段注释是否正常

sql 复制代码
DESC FORMATTED your_table_name;

如果 COMMENT 字段显示为 ??? 或乱码,基本就是元数据字符集问题。

2. 检查并修改 Hive 元数据库(MySQL)字符集

登录 MySQL 元数据库

sql 复制代码
-- 查看 Metastore 数据库的字符集设置
SHOW VARIABLES LIKE 'character_set%';
-- 查看具体表的字符集
SHOW CREATE DATABASE metastore;

修改元数据库中相关表的字段字符集为 UTF-8

sql 复制代码
use metastore;

-- 修改表注释(TABLE_PARAMS)的字符集
ALTER TABLE TABLE_PARAMS MODIFY COLUMN PARAM_VALUE VARCHAR(4000) CHARACTER SET utf8;

-- 修改字段注释(COLUMNS_V2)的字符集
ALTER TABLE COLUMNS_V2 MODIFY COLUMN COMMENT VARCHAR(256) CHARACTER SET utf8;

-- 修改分区参数(PARTITION_PARAMS)的字符集(如有)
ALTER TABLE PARTITION_PARAMS MODIFY COLUMN PARAM_VALUE VARCHAR(4000) CHARACTER SET utf8;

3. 检查数据文件本身的字符集

可以通过 Linux 命令 file -i 数据文件名 查看文件编码是否为 utf-8

如果源文件是 GBK,需要使用 iconv 等工具进行转码后再加载。

4. 查询/修改当前会话的字符集

在执行查询前,可以设置当前会话的字符集:

sql 复制代码
-- 设置当前会话字符集为 UTF-8
SET character_set_client = utf8;
SET character_set_results = utf8;
SET character_set_connection = utf8;

-- 或者直接使用 SET NAMES 命令(效果等同于上面三条)
SET NAMES 'utf8';

三、中文乱码处理实战

场景1:Oracle 查询出来的中文是问号/乱码

原因:客户端字符集(NLS_LANG)与服务端不一致。


解决方案:统一客户端 NLS_LANG 设置。

  • Linux/Unix 环境

    bash 复制代码
    export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
    # 或者
    export NLS_LANG="AMERICAN_AMERICA.AL32UTF8"
  • Windows 环境

    • 打开注册表编辑器(regedit)

    • 找到路径 HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\KEY_OracleHome

    • 修改或新建字符串值 NLS_LANG,设置为服务端一致的字符集(如 SIMPLIFIED CHINESE_CHINA.ZHS16GBK

设置 NLS_LANG 后必须重启客户端才能生效。

场景2:Hive 建表时 COMMENT 显示乱码

原因 :Hive 的元数据存储在 MySQL 中,默认字符集可能是 latin1,不支持中文。


解决方案 :参照"第二部分:Hive 元数据乱码解决",修改 Metastore 相关表的字段字符集为 utf8

场景3:数据迁移过程中出现的乱码

排查思路

  1. 检查源文件编码 :是否为 UTF-8Hive 对 UTF-8 支持最好)。

  2. 检查导入方式 :使用 LOAD DATA 命令时,可尝试加上 CHARSET 'UTF-8' 参数(取决于具体版本)。

  3. 使用转换函数:如果数据已经乱码,在 Hive 查询时可尝试通过内置函数进行修正:

    sql 复制代码
    -- 将 latin1 编码的列转换为 utf8 显示(慎用,取决于数据实际编码)
    SELECT conv(column_name, 'latin1', 'utf8') FROM table_name;

总结:最佳实践

环境 操作 核心命令/方法
Oracle 查看服务端字符集 SELECT * FROM nls_database_parameters;
Oracle 查看客户端字符集 SELECT userenv('language') FROM dual;
Oracle 修复乱码 修改环境变量 NLS_LANG 与服务端一致
Hive 查看元数据乱码 DESC FORMATTED table_name;
Hive 解决元数据乱码 修改 Metastore 数据库中相关表的字段字符集为 utf8
通用 设置会话字符集 SET NAMES 'utf8'; (MySQL)

一句话总结

Oracle 乱码先看 NLS_LANG,Hive 乱码先修 MySQL Metastore


在银行数据开发中,养成统一使用 UTF-8 编码的习惯,能避免 90% 的中文乱码问题。


在银行数据开发中,养成统一使用 UTF-8 编码的习惯,是什么意思?不是说有的表的格式不能随便修改,而且改编码是需要更高权限才行?


你这个追问非常到位,说明你已经在用生产环境的思维考虑问题了,而不仅仅是学语法。


核心结论

"养成统一使用 UTF-8 编码的习惯"不是让你去改生产表 ,而是让你在新建表、写 ETL、导文件时主动选 UTF-8,并理解乱码产生的根源。


下面分三个层次帮你彻底搞清楚。


一、"养成使用 UTF-8 习惯"到底是什么意思?

这句话针对的是你可以控制的范围,不是让你去动老旧系统。

范围 你能做的 不能做的
新建表 建表时指定 CHARSET=utf8 ---
ETL 中间文件 CSV/Parquet 统一用 UTF-8 ---
数据交换 接口文件、Kafka 消息用 UTF-8 ---
历史表 / 老旧系统 不要乱改 不要自己改 Oracle / MySQL 元数据

一句话

从你手里出去的东西,尽量用 UTF-8。存量系统,按它原来的编码处理,不乱动。


二、为什么不能随便改?你说得很对

你说的是事实:

1️⃣ 改表编码确实需要更高权限

  • 修改 Hive Metastore 字符集

    → 需要 MySQL 的 ALTER 权限,普通开发没有

  • 修改 Oracle 数据库字符集

    → 需要 DBA 权限 + 停业务 + 重建库,几乎不可能让你干

2️⃣ 改编码可能造成更严重的乱码

text

复制代码
GBK → 强制转 UTF-8(不按规则转)
=> 变成 UTF-8 环境下的“乱码永久化”
=> 比原来还难修

3️⃣ 表格式不能随便改

  • 历史表下游依赖很多

  • 你改了编码 → 下游 ETL / 应用 全部可能报错

所以

存量表不是你的事,是 DBA + 数据治理 + 业务方一起决定的事。


三、银行实际工作中怎么处理编码问题?

场景 1:你新建一张表(你有控制权)

正确做法:主动用 UTF-8

Hive

sql

复制代码
CREATE TABLE my_table (
  id INT,
  name STRING
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE
TBLPROPERTIES ('serialization.encoding'='UTF-8');

如果底层存储是 ORC / Parquet,已经是二进制,不存在编码问题

MySQL(极少作为数仓,但可能用)

sql

复制代码
CREATE TABLE my_table (
  id INT,
  name VARCHAR(100)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

场景 2:你发现历史表乱码(你不能改表)

错误做法

  • 提工单要求 DBA 改表编码

  • 自己写 ALTER 命令

正确做法(数据层解决)

Hive 查询时转换

sql

复制代码
SELECT 
  col,
  CONVERT(col USING UTF8) AS col_utf8
FROM old_table;
Sqoop 导出 / 导入时指定编码

bash

复制代码
-- 强制使用 UTF-8
--map-column-java "name=String" \
--map-column-hive "name=STRING" \
--fields-terminated-by '\001' \
--null-string '\\N' \
--null-non-string '\\N' \
--connect "jdbc:mysql://host/db?useUnicode=true&characterEncoding=UTF-8"

场景 3:两个异构系统对接(最真实)

  • Oracle(GBK) → Hive(UTF-8)

  • 你不能改 Oracle

正确做法在 ETL 中转码

bash

复制代码
# 导出阶段指定编码
sqlplus user/pwd@orcl
set NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK
spool data.csv

# 导入 Hive 时明确使用 UTF-8
LOAD DATA INPATH '/path/data.csv'
INTO TABLE hive_table
-- 明确文件编码
-- 部分版本支持
WITH SERDEPROPERTIES ('serialization.encoding'='UTF-8');

四、一个你一定能听懂的比喻

改表编码 ≈ 把一仓库老账本的文字全用修正液改一遍

  • 你可以从今天开始用新本子(新表)

  • 但不能动老账本(历史表)

  • 老账本看不懂时,你可以配翻译(ETL 转码)

✅ 你问的"不能随便改"、"要更高权限"

完全正确,不是你能动的事情


五、面试 / 工作中可以这样说(非常加分)

*"我理解,编码问题不是随便改表。我的原则是:新表主动用 UTF-8;存量表不动;乱码在 ETL 层用转码函数或调整连接参数解决。如果全局改编码,会申请 DBA 配合,并经过充分测试。"*


总结(请你记住这三条)

情况 你能不能改 怎么办
新建表 ✅ 可以 主动指定 CHARSET=utf8
老表乱码 ❌ 不能 ETL 中转码 / 查询时转换
两个系统不一致 ❌ 不能 导出 / 导入时统一编码(不碰表)

"养成 UTF-8 习惯"不是改历史,而是规范未来。


不越权、不瞎改、不假设,这是银行数据开发的底线。

相关推荐
Irene199139 分钟前
Oracle 连接避坑指南:环境+配置+账号
数据库·oracle
鹿鸣天涯2 小时前
应急响应:MySQL日志分析
mysql·安全·adb·oracle
snow@li17 小时前
MyBatis:动态 SQL 全景梳理
数据库·sql·mybatis
z落落18 小时前
T-SQL 事务(Transaction)
java·数据库·sql
ClouGence20 小时前
MySQL迁移到达梦怎么做?信创数据库低停机迁移实战
数据库·sql·mysql
仙宇觉尘1 天前
记一次 .NET 某中医药附属医院门诊系统 崩溃分析
数据库·oracle·.net
NineData1 天前
Oracle 长事务正在消耗 undo 空间,ChatDBA 能提前发现
数据库·sql·oracle·agent·ninedata·回滚·长事务
风曦Kisaki1 天前
MySql常用命令速查表
数据库·sql·mysql
北冥you鱼1 天前
Go语言 sql.Null 类型详解:处理数据库 NULL 值的正确姿势
数据库·sql·golang
北冥you鱼1 天前
Go语言 database/sql 包常见方法解析与最佳实践
数据库·sql·golang