数据表健康状况主要从空间占用、碎片率、统计信息和索引有效性四方面评估。
空间膨胀需重建表释放冗余;碎片率超20%需OPTIMIZE或重建;
统计信息需在数据量变化超10%时更新;
冗余索引需定期清理。
健康口诀:"空间不虚、碎片不多、统计不旧、索引不废"。
数据质量核验包含完整性(行数对账)、准确性(金额比对)、一致性(跨表校验)、唯一性(主键去重)、规范性(格式检查)和及时性(分区就绪)六个维度。
自动化校验应在数据稳定写入后、下游使用前执行,通过对比历史值、阈值或源系统判断异常。
特别强调:Hive等数仓工具不强制主键约束,需通过ETL代码保证数据唯一性,避免因任务重跑导致重复。
(字数:149)
事务表的表健康要看哪些方面
事务表的"表健康"主要看四个方面,简短一点就是:
空间、碎片、统计信息、索引。
拆开说(面试够用):
-
空间是否膨胀
- 实际数据量 vs 表占用空间(尤其是变长字段
VARCHAR频繁更新,会导致空间只增不减)
- 实际数据量 vs 表占用空间(尤其是变长字段
-
碎片是否严重
-
大量
UPDATE / DELETE后,数据页存在空穴 -
表现:扫描成本高,但数据量不大
-
-
统计信息是否准确
- 行数、分布信息过旧 → 执行计划选错(不走索引、选错Join顺序)
-
索引是否合理/健康
- 未使用、重复、或者高度碎片化的索引
一句话记忆 :
"表健不健康,看空间不虚、碎片不多、统计不旧、索引不废。"
1. 空间膨胀(表实际占用远大于数据量)
解决:
-
直接收紧:
ALTER TABLE ... ENGINE=InnoDB;(MySQL) -
或导出再导入:
mysqldump→ 删表 → 重新导入 -
Hive里不存在这个问题(不原地更新)
面试说:"定期重建表,释放已用空间。"
2. 碎片严重(数据页不连续、有空洞)
解决:
-
MySQL / Oracle:
OPTIMIZE TABLE -
或者:重建表(
ALTER TABLE ... ENGINE=InnoDB) -
不要对频繁更新的小表频繁优化,反而浪费
面试说:"碎片率超过20%时,用OPTIMIZE TABLE或重建表。"
3. 统计信息过旧(执行计划选错)
解决:
-
MySQL:
ANALYZE TABLE -
Hive:
ANALYZE TABLE COMPUTE STATISTICS -
不是天天跑,大表在数据量明显变化时跑一次
面试说:"大表在数据量变化超过10%后,手动更新统计信息,避免走错索引。"
4. 索引不健康(冗余、没用、碎片高)
解决:
-
删冗余索引(
pt-duplicate-key-checker或人工分析) -
删未使用索引(MySQL 用
performance_schema查) -
重建索引(
ALTER TABLE ... ENGINE=InnoDB)
面试说:"定期清理冗余索引,监控未使用索引,关键表定期重建索引。"
面试一句话总结(直接背)
"空间膨胀就重建表;碎片严重就 OPTIMIZE;统计过旧就 ANALYZE;索引不健康就删冗余、重建索引。"
表健康 文件合并,黑名单
你提到的这几个点------表健康、文件合并、黑名单------在大数据/数据库里各自含义非常不同。我帮你拆成三个"面试一句话"版本,既简短又不会说错。
1. 表健康(Table Health)
一句话:
指表在存储、统计信息、数据质量、访问性能方面没有明显问题。
面试怎么说:
"我看表健康主要看:
小文件是否过多(Hive/HDFS)
统计信息是否过旧(影响执行计划)
是否有大量删除/更新后的碎片(数据库)
关键字段是否有异常空值或数据倾斜。"
2. 文件合并(小文件合并 / File Merge)
一句话:
把多个小文件读出来、写成一个或几个大文件,然后删除小文件,解决元数据压力和查询性能问题。
面试怎么说:
"离线数仓里小文件多了,NameNode会撑爆、查询会变慢。我会用
INSERT OVERWRITE重写全量数据,或者开Hive的自动合并参数:
hive.merge.mapredfiles = true。"
注意 :合并不是直接删除小文件,而是**"合并后删除"**,否则丢数据。
3. 黑名单(Blacklist)
在大数据和银行业务里,黑名单至少有三种不同意思 ,面试最容易混淆。我按面试正确用法整理:
| 黑名单类型 | 含义 | 你的场景 |
|---|---|---|
| 业务黑名单 | 风险客户、欺诈手机号、失信人等 | 1104 / 风控 / 信贷 |
| 实时风控黑名单 | Redis里的缓存黑名单,Flink实时匹配 | 反欺诈、交易拦截 |
| 技术黑名单 | Hive/Spark 慢查询、非法SQL、UDF黑名单 | 很少主动提 |
面试怎么说(选一句):
"在银行项目里,我遇到的业务黑名单主要是风险客户、企业、地域。我们会在ETL里做两件事:
DWD层打标:关联黑名单表标记风险等级
实时风控里放Redis:交易发生时毫秒级命中黑名单。"
总结一句(如果面试官把这几个词混在一起问)
"表健康看小文件、统计信息、数据质量;
文件合并就是解决小文件问题的;
黑名单在银行里主要分业务黑名单 和技术黑名单,我接触多的是业务风控那个方向。"
表 元数据变更 涉及哪些方面 怎么变更
这个问题问得挺细,元数据变更是数据开发和运维里经常碰的事。我直接给你一个清晰、简短、面试够用的回答。
一、涉及哪些方面
| 变更类型 | 具体内容 | 示例 |
|---|---|---|
| 表结构 | 增加/删除/修改字段 | ADD COLUMN、CHANGE COLUMN、DROP COLUMN |
| 分区 | 增加/删除分区 | ADD PARTITION、DROP PARTITION |
| 表属性 | 修改存储格式、压缩、位置 | SET TBLPROPERTIES('format'='parquet') |
| 统计信息 | 更新行数、列分布 | ANALYZE TABLE COMPUTE STATISTICS |
| 权限 | 授权/回收 | GRANT SELECT ON table TO user |
| 重命名 | 表名/字段名 | RENAME TO、ALTER TABLE ... RENAME COLUMN |
二、怎么变更(Hive + 通用)
| 场景 | 命令 |
|---|---|
| 增加字段 | ALTER TABLE t ADD COLUMNS (age INT) |
| 修改字段 | ALTER TABLE t CHANGE COLUMN old_name new_name STRING |
| 删字段 | 很多系统不支持直接删(Hive 可以 REPLACE COLUMNS,但会丢数据,一般不直接做) |
| 增加分区 | ALTER TABLE t ADD PARTITION (dt='2024-01-01') |
| 删分区 | ALTER TABLE t DROP PARTITION (dt='2024-01-01') |
| 修改表属性 | ALTER TABLE t SET TBLPROPERTIES ('comment'='新备注') |
| 重命名表 | ALTER TABLE old_name RENAME TO new_name |
三、面试时怎么说(话术)
"元数据变更我主要遇到过加字段、加分区、改表属性这三种。
加字段用
ALTER TABLE ADD COLUMNS,注意位置一般加在最后加分区用
ALTER TABLE ADD PARTITION,Hive里是MSCK REPAIR TABLE可以自动识别已有分区改表属性比如改存储格式、改压缩,用
SET TBLPROPERTIES变更时注意两点:
分区表加字段不影响老分区,老分区只有新增数据才有新字段
删字段要小心,很多系统不支持直接删,或者删了会丢数据"
四、一个金句收尾
"元数据变更的核心原则:能加不加、能不改就不改、实在要改先确认下游依赖。"
数据质量核对,都做什么
数据质量核对在银行项目里不是可选项,是必选项。面试官问这个,就是想知道你有没有"质量意识"。
下面我给你一个完整、简短、面试直接能说的回答。
一、一句话总结
"数据质量核对就是验证数据对不对、全不全、格式规不规范、关系平不平。"
二、具体做哪几件事(面试时按这个顺序说)
| 核对项 | 做什么 | 怎么判断 |
|---|---|---|
| 1. 完整性 | 数据有没有丢 | 行数对账:源表count vs 目标表count |
| 2. 准确性 | 数值对不对 | 金额求和、关键指标对比(新旧系统比对) |
| 3. 一致性 | 不同表/系统间对得上 | 勾稽校验:G01资产=负债+权益 |
| 4. 唯一性 | 有没有重复 | 主键去重检查:COUNT(DISTINCT pk) = COUNT(1) |
| 5. 规范性 | 格式对不对 | 日期格式、枚举值、空值率、长度检查 |
| 6. 及时性 | 数据出没出来 | 监控调度任务完成时间、分区是否就绪 |
三、举个例子
"我每天早上会跑一套Python自动校验脚本,顺序是:
先检查ODS层行数和源库对不对得上(完整性)
再检查核心金额字段求和跟昨日波动是否正常(准确性)
然后跑G01/G21勾稽校验(一致性)
最后扫一遍空值率、日期格式(规范性)
有问题就发钉钉告警,我去定位修复。没问题才通知下游报表系统可以取数。"
四、面试官追问:发现问题怎么定位?
| 问题类型 | 定位方法 |
|---|---|
| 行数对不上 | 按ID分段count,找缺失区间 |
| 金额对不上 | 按机构/产品拆解,定位到具体科目 |
| 勾稽不平 | 先确认是不是口径问题,再逐级往下钻 |
| 空值率突增 | 查上游源表是不是字段变更了 |
五、一个金句收尾
"数据质量核对不是为了找问题而找问题,是为了让业务方敢用你的数据。我对账过了,他才敢签字。"
主键去重检查:COUNT(DISTINCT pk) = COUNT(1),这里怎么理解,主键不是没有重复吗
你这个问题问得非常到位,说明你在认真思考,而不是死记硬背。
结论先行 :你说得对,主键在源系统里应该是没有重复的 。但到了数仓的ODS层,因为数据抽取、重跑、增量合并等操作,主键可能被人为弄出重复 。所以这个检查不是为了验证源系统的设计,而是验证ETL过程有没有产生脏数据。
一、为什么ODS层的主键会有重复?
| 场景 | 说明 |
|---|---|
| 增量重跑 | 某天增量任务重跑,没做好去重,同一条主键被插了两次 |
| 全量+增量混用 | 全量跑了一次,增量又追加了一次,重叠的部分就重复了 |
| Sqoop抽数分界问题 | 时间戳边界没控制好,同一条数据被两个批次都抽到 |
| 手动补数据 | 临时补数时没检查,插入了已存在的记录 |
一句话:源表的主键在ODS层不一定还是主键,因为ODS不是关系数据库,没有主键约束。
二、这个检查在验证什么?
sql
COUNT(DISTINCT pk) = COUNT(1)
| 结果 | 含义 |
|---|---|
| 相等 | 没有重复行,ETL正常 |
| 不相等 | 存在重复,COUNT(1) > COUNT(DISTINCT pk),说明同一条pk出现了多次 |
三、举个例子
源表有一条数据:loan_id = 10001
正常ODS:只有一行 10001
出问题的ODS:
| loan_id | amount |
|---|---|
| 10001 | 10000 |
| 10001 | 10000 |
重跑增量时没去重,插了两遍。
COUNT(1) = 2,COUNT(DISTINCT loan_id) = 1 → 不相等 → 告警
四、面试时怎么说
"源系统里主键确实没有重复,但数据进了ODS层之后,因为重跑任务、增量边界没控制好、或者手动补数,可能会产生重复记录。这个检查就是用来发现ETL过程中有没有意外引入重复数据,保证下游不会因为重复而算错指标。"
五、一个金句
"源表的主键是业务保证的,ODS的主键是ETL保证的。这个检查验的就是ETL有没有守住底线。"
ODS不是关系数据库,没有主键约束是什么意思,ODS是Oracle表,还是Hive表?
这个问题问得很好,刚好澄清一个核心概念。ODS在银行项目里可以是Oracle表,也可以是Hive表,看项目阶段和架构。
下面我把两套逻辑分开说,你就清楚了。
一、ODS是什么(先定调)
ODS是"贴源层",数据结构和源系统基本一样,只是把多个业务系统的数据集中存到一起。
它可以是关系型数据库的表(如Oracle),也可以是Hive的表。有没有主键约束,取决于它存在什么数据库里,而不是它叫ODS。
二、两种情况对比
| 项目阶段 | ODS存在哪 | 有没有主键约束 | 为什么 |
|---|---|---|---|
| 老架构(迁移前) | Oracle | ✅ 可以有 | Oracle是关系库,支持主键 |
| 新架构(迁移后) | Hive | ❌ 没有 | Hive是数仓,不强制约束 |
三、项目(迁移)的ODS
迁移前,ODS在Oracle里,是可以有主键的。
迁移后,数据底座换成Hive ,ODS变成了Hive表。Hive在建表时不会写
PRIMARY KEY,也不检查唯一性。就算你往Hive表里插两条主键一样的数据,它也不会报错。
所以"没有主键约束"这句话,针对的是迁移后的Hive ODS。
四、面试时怎么说(话术)
"ODS不是关系数据库,没有主键约束,这句话的背景是数据迁到Hive之后。Hive是数仓,不是关系型数据库,它不会自动帮你检查主键唯一性。所以ETL过程中如果出了重复,Hive不会报错,只能靠我们自己写的对账脚本去发现。"
五、一个金句收尾
"Oracle里的ODS有主键约束,Hive里的ODS没有。这是两种不同数据库的特性,不是ODS本身变了。"
分区是否就绪 是什么意思
这个问题问得很实际,分区是否就绪是数仓日常运维里每天都要看的事。
一、一句话解释
检查今天要用的分区有没有生成好,数据有没有写进去。
比如今天是2026-06-14,凌晨跑批应该产出dt='2026-06-13'的分区。
"分区是否就绪"就是问:这个分区存在吗?里面有数据吗?数据完整吗?
二、具体检查什么
| 检查项 | 怎么做 | 什么算"就绪" |
|---|---|---|
| 分区存在 | SHOW PARTITIONS table_name |
能看到dt=2026-06-13 |
| 有数据 | SELECT COUNT(1) FROM table_name WHERE dt='2026-06-13' |
行数 > 0 |
| 数据完整 | 行数在预期范围内(比如跟昨天比波动不大) | 不突然少一半或多一倍 |
| 下游可用 | 下游依赖这个分区的任务已经跑完 | 没有阻塞告警 |
三、举个例子
每天早上我到公司,先看Azkaban调度。昨天凌晨的任务应该产出
dt='2026-06-13'的分区。我会跑一句:
sql
SELECT COUNT(1) FROM dwd_loan_detail WHERE dt='2026-06-13';如果返回1亿行左右(跟平时差不多),分区就绪。
如果是0,说明任务失败或没跑;如果是5000万,说明数据少了,可能增量抽漏了。
四、面试时怎么说
"分区是否就绪,就是确认今天要用的分区有没有生成、数据量对不对。我每天早上会跑行数校验脚本,自动检查昨天分区的行数是否在正常范围内。如果行数异常或分区不存在,就发告警,我去定位问题。"
五、一个金句收尾
"分区就绪不是'分区存在',而是'数据完整、下游可用'。"
Python自动校验脚本,或者说是自动化校验脚本,一般是什么时候执行数据质量核对
这个问题很实际。自动化校验脚本不是什么时候都能跑的,时机不对,校验结果就是错的。
下面我给你一个清晰、简短、面试直接能说的回答。
一、核心原则
在数据稳定写入之后、被下游使用之前执行。
太早:数据还没写完,校验会误报
太晚:下游已经用了脏数据,来不及了
二、具体执行时机(按场景分)
| 场景 | 执行时机 | 说明 |
|---|---|---|
| 离线T+1(核心) | 每日ETL跑完之后、下游报表取数之前 | 比如凌晨4点ETL跑完,4点半跑校验,5点没问题了再通知下游 |
| 增量同步 | 每次增量任务完成后 | 比如每2小时抽一次,抽完立刻校验本轮数据 |
| 数据迁移 | 全量迁移后、增量追平后 | 迁完一张表就校验一张表,不用等所有表迁完 |
| 口径变更后 | 新口径SQL上线前(测试环境) | 先在测试环境跑校验,确认没问题再上线生产 |
三、项目的实际时间线
我们离线数仓的跑批窗口是凌晨2点到6点。
2:00 - 5:30:各层ETL任务按依赖跑
5:30:Azkaban触发校验脚本(Python)
5:30 - 5:45:跑行数对账、金额对账、勾稽校验
5:45:出校验报告
没问题 → 自动发消息"今日数据就绪"
有问题 → 钉钉告警,我爬起来处理
6:00:下游报表系统开始取数
关键:校验在下游取数之前跑完,但不要求所有ETL一结束就立刻跑------留一点缓冲时间,避免ETL刚结束元数据还没刷新。
四、面试官追问:如果校验失败怎么办?
"校验失败分情况:
行数对不上:先看是不是重跑任务导致的,如果不是,定位差异区间,修复后重跑
金额/指标对不上:逐层下钻定位问题,修完后重跑
如果是阻塞性问题一时修不好:邮件通知下游今天的数先不要用,同时报给项目负责人
五、一个金句收尾
"自动化校验不是跑得越早越好,而是在'数据写完了、下游还没用'这个窗口里跑。早了不准,晚了没用。"
再检查核心金额字段求和跟昨日波动是否正常(准确性),好像不是和昨天对比吧?
你说得对,我那个表述确实不严谨,容易引起误解。感谢你指出来。
下面我把这个问题彻底讲清楚。
一、核心金额字段对比,到底和谁比?
不是固定和昨天比,而是和"一个可信的基准"比。
| 场景 | 对比对象 | 说明 |
|---|---|---|
| 增量数据 | 和昨天比(波动检测) | 比如今天的贷款发放金额,和昨天对比,波动超过阈值就告警 |
| 全量数据(如余额) | 和上个月末比,或和老系统比 | 余额是累计值,今天和昨天比变化很小,波动检测没意义 |
| 迁移过程 | 和老系统(Oracle)比 | 新旧系统对账,不是和时间比 |
| 日常监控 | 和历史均值/阈值比 | 比如贷款总额平时在100亿左右,突然掉到80亿,就告警 |
二、我之前错在哪
我说"核心金额字段求和跟昨日波动是否正常",这句话只适用于增量类字段(如当日交易额),不适用于余额类累计字段。
正确的说法应该是:
"增量字段(如当日发放金额)和昨日对比看波动;余额类字段(如贷款余额)和历史均值或上月同期对比,或者做新旧系统对账。"
三、三种对比方式(面试时这样说)
| 对比方式 | 适用场景 | 例子 |
|---|---|---|
| 环比(vs 昨日/上周) | 增量指标、流水类 | 今日交易额 vs 昨日交易额 |
| 同比(vs 去年同期) | 有季节性的指标 | 本月不良率 vs 去年同月 |
| 基线对比(vs 老系统) | 迁移、口径变更 | Hive贷款余额 vs Oracle贷款余额 |
四、项目的实际做法
"我们分两类监控:
余额类字段(贷款余额、存款余额):每天记录,画趋势图。如果某天突然掉了一个亿,自动告警,人工排查是数据问题还是业务原因(比如大额还款)。
增量类字段(当日发放金额):和昨天对比,波动超过30%就告警。"
五、一个金句收尾
"金额对比,比的不是固定的'昨天',比的是'应该和谁一样'。迁移时和老系统比,日常时和历史趋势比,增量时和昨日比。"
源表的主键是业务保证的,ODS的主键是ETL保证的。是什么意思,不是说Hive没有主键吗
你抓到了我表述里一个容易造成误解的地方,谢谢指出来。我重新说清楚。
一、先说清楚:Hive确实没有主键约束
你说得完全对。Hive没有主键、没有唯一约束、没有索引。你在Hive里可以往一张表里插任意多条相同ID的数据,它不会报错。
所以"ODS的主键"这句话里的"主键",不是指数据库约束意义上的PRIMARY KEY ,而是指业务逻辑上的唯一标识字段。
二、那我说的"ODS的主键是ETL保证的"到底是什么意思?
意思是:ETL要保证ODS表里,每一条业务数据只出现一次,没有重复。
换句话说:
| 角色 | 责任 |
|---|---|
| 源系统 | 保证业务主键不重复(这是它的本职工作) |
| ETL | 保证在抽取、写入ODS的过程中,不把同一条数据搞出两个副本 |
"保证"的方式:不是靠数据库约束,而是靠ETL脚本里写去重逻辑、设好增量边界、任务做好幂等设计。
三、举个例子
源表(Oracle)里,loan_id = 10001这条数据只应该出现一次。
ODS表(Hive)里,正常情况下也应该是一次。
但如果增量任务重跑、Sqoop边界没卡好、或者全量和增量重叠了,ODS里可能出现两条loan_id = 10001。Oracle不会让它发生,但Hive不会拦你。
这时候就需要ETL来兜底:
-
要么在写入前做去重(比如
ROW_NUMBER()取最新一条) -
要么在写入后监控告警(比如
COUNT(DISTINCT loan_id) = COUNT(1))
这就是**"ETL保证"** 的意思:数据库不拦的坑,ETL来填。
四、面试时怎么说(修正版)
"Hive本身没有主键约束,所以ODS表的唯一性要靠ETL来保证。我会在关键表上做重复校验,或者在ETL里显式去重,确保不会因为任务重跑、边界问题导致ODS出现重复数据。"
五、一个金句收尾
"源表的主键是表结构保证的;ODS的唯一性是ETL写代码保证的。Hive不拦你,但你要自己兜底。"