主键的作用:
唯一标识每一行数据
主键(Primary Key) 的取值必须唯一,且不能为NULL
什么是外键?
外键是一个表中的字段,它的值必须匹配另一张表(或同一张表)的主键值。
外键的核心是建立和强制两张表之间的引用关系 ,从而保证数据的逻辑一致性。
什么是关系型数据库?
RDBMS的核心特性(如强事务、实时更新、严格的ACID)
关系型数据库的"关系"是什么?
"关系" 在关系型数据库中,本源是数学上的集合关系,具体表现为二维表,并通过SQL操作。
它主要包含以下三层含义,层层递进:
第一层:数学基础------关系代数(核心本源)
这是"关系"一词的真正来源。
-
"关系"在这里是一个数学集合论中的概念 。具体指:多个集合的笛卡尔积的一个子集。
-
通俗化解释 :想象一个"学生"表,它有学号、姓名、年龄三个字段。这个表在数学上就是一个"关系",它代表了所有可能的(学号,姓名,年龄)组合中,实际存在的那些数据行所构成的集合。
-
关键点 :这个"关系"是值的集合 ,是无序的,强调的是数据的逻辑集合本身,而不是其物理存储形式。
对"关系"(即表)的操作,遵循一套完整的数学理论------关系代数。
-
其核心操作包括:选择(σ)、投影(π)、连接(⋈)、并集(∪) 等。
-
SQL语言 正是基于关系代数设计的。当你写
SELECT ... FROM ... WHERE ... JOIN ...时,你就是在描述一系列关系代数运算。 -
所有操作的结果仍然是一个"关系"(一张新表),这使得操作可以层层组合,非常强大和灵活
第二层:数据结构------二维表(具体表现)
在计算机中,我们用二维表来直观地表示和操作这个数学上的"关系"。
-
一个"关系" = 一张表(Table)
-
关系的属性(Attribute) = 表的列(Column)
-
关系的元组(Tuple) = 表的行(Row)
-
这种结构极其清晰、直观,符合人类理解数据的习惯。
关系模型的三要素:
-
数据结构:二维表(关系)。
-
操作方式:关系代数/SQL。
-
完整性约束:实体完整性(主键)、参照完整性(外键)、用户自定义完整性
关系型数据库的核心特征总结
基于关系模型构建的数据库(RDBMS)通常具备以下特征:
-
数据以二维表形式呈现。
-
支持SQL语言进行数据定义和操作。
-
支持ACID事务,保证数据一致性(这是Oracle/MySQL等OLTP数据库的强项)。
-
支持完整性约束(主键、外键等)。
关系型数据库的完整性约束是什么?实体完整性(主键)、参照完整性(外键)、用户自定义完整性?
| 约束类型 | 中文名称 | 英文名称 | 核心作用 | 典型实现机制 |
|---|---|---|---|---|
| 实体完整性 | 实体完整性 | Entity Integrity | 保证表中每行数据的唯一可标识性 | 主键(Primary Key) 约束 |
| 参照完整性 | 参照完整性 | Referential Integrity | 保证表与表之间引用关系的一致性 | 外键(Foreign Key) 约束 |
| 用户自定义完整性 | 用户自定义完整性 | User-defined Integrity | 保证数据符合具体的业务规则 | **检查(CHECK)、唯一(UNIQUE)、非空(NOT NULL)、默认值(DEFAULT)、触发器(Trigger)**等 |
1. 实体完整性
主键(Primary Key) 的取值必须唯一,且不能为NULL。
-
为什么重要:
-
唯一标识:确保表中的每一行都是一个可区分的"实体"。就像每个人有唯一的身份证号。
-
操作基础 :是数据更新、删除和关联查询的唯一依据。
-
2.参照完整性
-
定义 :如果表A中的某个字段(外键)引用了表B的主键,那么该外键的取值要么为NULL,要么必须在表B的主键值中存在。
-
为什么重要:
-
防止"孤儿数据":确保不会出现引用了一个不存在实体的数据。比如,不会出现一笔交易对应的账户在账户表中不存在。
-
维护数据关联网络:保证整个数据库内数据关系的逻辑一致性。
-
-
银行实例:
-
交易流水表中有一个账号(ACCT_NO)字段,它作为外键 ,引用了账户表的主键ACCT_NO。 -
这意味着,任何一笔交易记录中的
ACCT_NO,都必须在账户表中真实存在。
-
-
违反示例:
-
试图在
交易流水表中插入一条ACCT_NO = '9999999999'的记录,而账户表中根本没有这个账号。数据库会拒绝插入。 -
如果试图从
账户表中删除一个还有交易流水关联的账户,数据库的典型行为是:-
RESTRICT(默认) :拒绝删除,除非先删除所有关联流水。
-
CASCADE :级联删除,自动删除所有关联的流水记录(风险高,银行慎用)。
-
SET NULL:将流水表中的外键设为NULL(通常不符合业务逻辑)。
-
-
银行实例:
客户信息表中,客户号(CUST_ID)必须设为主键。这保证了一个客户号只对应一个真实的客户,避免重复开户或信息混淆。
3. 用户自定义完整性
-
定义 :根据具体业务需求定义的、超出上述两种基本完整性之外的规则。最为灵活,也最体现业务特性。
-
为什么重要:将业务规则固化在数据库层面,从源头保证数据质量,避免脏数据流入。
-
常见实现机制与银行实例:
| 机制 | 银行实例 | SQL示例(简写) |
|---|---|---|
| 非空约束 | 客户姓名不能为空 | CUST_NAME VARCHAR(100) NOT NULL |
| 唯一约束 | 客户身份证号不能重复(即使它不是主键) | ID_NO VARCHAR(18) UNIQUE |
| 检查约束 | 账户余额不能为负数 客户年龄必须大于等于18岁 交易金额必须大于0 | BALANCE DECIMAL(15,2) CHECK (BALANCE >= 0) AGE INT CHECK (AGE >= 18) TX_AMT DECIMAL(15,2) CHECK (TX_AMT > 0) |
| 默认值 | 账户开户日期默认为系统当前日期 | OPEN_DATE DATE DEFAULT CURRENT_DATE |
| 触发器 | 更复杂的业务规则: 1. 当账户余额变更时,自动插入一条余额变更流水。 2. 当单日交易累计金额超过5万时,发送预警。 3. 确保贷款状态与还款计划状态的逻辑一致。 | 通过 CREATE TRIGGER 实现的一段PL/SQL或T-SQL程序。 |
Hive和MySQL Oracle在延迟上有什么不同?
MySQL和Oracle毫秒到秒级, Hive:分钟到小时级
银行数仓使用Hive这个非关系型数据库,是没有主键的。如果不小心录入了一个新开户信息,身份证号和hive数据库里面的身份证号相同,但是名字信息不同,是不是不会报错?那也不容易发现这样的错误?
为什么Hive不会报错?
-
无主键约束 :Hive不强制id_no字段的唯一性。
-
无唯一约束 :即使声明了
UNIQUE(Hive 3.x支持语法),默认也不强制执行。 -
批量处理特性 :Hive设计为高吞吐批处理,将数据质量检查交给上游应用。
三、具体业务情境:何时会遇到这种重复?
情境1:新分行开户时的信息录入错误(最常见)
-
场景:客户"张三"在A分行已有账户,姓名录入为"张三"。
-
问题:同一客户到B分行开户,柜员误录入为"张叁"。
-
结果 :核心系统创建了新的客户记录(新的customer_id),但身份证号相同。
-
进入数仓 :ETL拉取时会发现同一
id_no对应两个name值。
情境2:客户信息变更未同步
-
场景:客户"张三"改名为"张四",在开户行更新了信息(更新了C001记录)。
-
问题:但该客户在其他分行的账户信息(C002记录)未同步更新。
-
结果:核心系统存在两条同一身份证的记录,姓名不同。
-
进入数仓:ETL看到"历史姓名"和"新姓名"的冲突。
情境3:渠道数据不一致
-
场景:
-
线下渠道:客户实名认证为"张三"
-
线上渠道(手机银行):客户注册时自填为"张叁"
-
-
结果:银行不同渠道系统可能为同一客户创建了不同客户ID。
-
进入数仓:多渠道数据整合时发现冲突。
情境4:数据迁移或系统合并
-
场景:银行A并购银行B,两个核心系统合并。
-
问题:同一客户在两个银行都有账户,但客户信息(姓名简繁体、空格等)有细微差异。
-
结果:系统合并后,出现"重复"客户记录。
-
进入数仓:ETL需要处理这种历史遗留问题。
三、这种错误的严重性(在银行场景下)
这种"同人不同名"的错误极其危险:
| 影响层面 | 具体后果 |
|---|---|
| 客户视角 | 1. 客户征信记录混乱 2. 同一身份证号可能获得多份授信额度 3. 风险评级不一致,导致风控失效 |
| 业务视角 | 1. 同一客户被重复营销,成本浪费 2. 客户资产统计翻倍,报表失真 3. 反洗钱监控失效(无法关联同一人的所有交易) |
| 监管视角 | 1. 违反"了解你的客户"(KYC)原则 2. 监管报送数据不准确,面临重罚 3. 无法满足《反洗钱法》对客户身份识别的要求 |
真实案例:某银行曾因客户信息重复,导致同一客户在不同分行获得多笔贷款,最终形成集中度风险,被监管处罚。
一、真实案例:从新闻到监管罚单
案例1:某大型银行因客户身份信息不符被重罚(2022年)
-
事件 :监管检查发现,该银行客户信息系统中,同一身份证号对应多个不同姓名的客户记录超过万条。
-
后果:
-
反洗钱监控失效:无法有效识别同一客户的多账户异常交易
-
信贷过度集中:同一客户在不同分行获得多笔贷款,突破集中度限额
-
监管处罚 :因违反《金融机构客户身份识别和客户身份资料及交易记录保存管理办法》被罚款数百万元
-
-
根本原因:各分行录入客户信息时标准不统一,且总行缺乏有效的去重和校验机制。
案例2:城商行"一人多卡"套现案(2021年)
-
事件 :犯罪分子利用银行系统漏洞,使用同一身份证但不同姓名拼音(如"Zhang San"和"Zhang San1")在多个网点开立账户。
-
手法:
-
利用柜员录入疏忽(英文名大小写、空格差异)
-
在不同支行分别申请信用卡
-
通过虚假交易套现
-
-
暴露问题 :银行风险系统未将
ID_NO=110101199001011234, NAME=ZHANG SAN和ID_NO=110101199001011234, NAME=ZHANG SAN1识别为同一客户。
案例3:某股份制银行监管报送数据错误(2020年)
-
事件:向人民银行报送的"同一客户贷款总额"统计严重失实。
-
发现:检查发现,因客户姓名录入差异(简体/繁体、有无中间空格),导致:
-
一个实际贷款5000万的客户,被统计为3个"不同客户"
-
每个"客户"贷款额都不超过2000万
-
掩盖了单一客户集中度风险
-
-
处罚:因"报送金融统计报表错误"被警告并罚款。
四、银行的应对策略:如何发现并防止?
银行绝不会依赖Hive自身的约束,而是通过一整套数据治理体系来保证数据质量:
策略1:ETL过程中的强制去重(最核心防线)
在数据入仓的ODS→DWD层清洗时,就必须进行去重:
sql
-- 示例:使用窗口函数确保身份证号唯一
INSERT OVERWRITE TABLE dwd_customer
SELECT
cust_id,
id_no,
name,
-- 其他字段...
FROM (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY id_no
ORDER BY update_time DESC, data_source_priority
) AS rn
FROM ods_customer
WHERE id_no IS NOT NULL -- 非空检查
) t
WHERE rn = 1; -- 只取每个身份证号最新的一条记录
策略2:建立专门的数据质量监控(DQC)
银行数仓通常有独立的数据质量监控平台,定期扫描:
sql
-- 质量检查SQL:找出重复的身份证号
SELECT id_no, COUNT(*) as cnt,
COLLECT_SET(name) as names, -- 收集不同的名字
COLLECT_SET(cust_id) as cust_ids
FROM dim_customer
WHERE id_no IS NOT NULL
GROUP BY id_no
HAVING COUNT(*) > 1
-- 结果会推送到数据质量告警平台,通知负责人处理
策略3:引入数据湖表格式(现代解决方案)
使用Apache Hudi/Iceberg 等支持主键级更新的表格式:
-- Hudi示例:使用id_no作为主键进行Upsert
-- 如果id_no已存在,则更新记录;否则插入
-- 这本质上实现了“主键”的更新语义
Hive与MySQL/Oracle的区别,优势,劣势
响应速度上,MySQL/Oracle是秒级/毫秒级,Hive是分钟级/小时级
设计哲学不同:
Hive :面向批处理 和离线分析,设计目标是处理TB/PB级数据的复杂查询
MySQL/ Oracle :面向实时事件响应 ,是OLTP(在线事务处理)数据库的特性
Hive没有主键和索引,有可能存在主键重复的情况
Hive中没有触发器Trigger,因为触发器 是面向实时事件响应,是OLTP(在线事务处理)数据库的特性。
Hive中没有存储过程Procedure和Function
Hive的批处理是什么?
批处理 = 把一批数据攒到一起,定时 / 定量后一次性集中处理。
就像:
- 不是来一件快递就送一次,而是攒满一车再统一派送
- 不是洗一件衣服就开一次洗衣机,而是攒一桶再一起洗
放到银行 / 大数据里就是:
- 白天业务系统产生交易、还款、逾期、开户等数据
- 晚上 24:00 或凌晨 2:00 统一抽取到数仓
- 一次性计算:不良率、入催率、延滞率、迁徙率、拨备覆盖率等
- 第二天早上出报表给业务 / 风控部门看
HiveSQL里面有触发器吗?一般下面这种操作是在做分析的数仓里面,还是Oracle里面直接做了
-
当账户余额变更时,自动插入一条余额变更流水。
-
当单日交易累计金额超过5万时,发送预警。
答案是:没有。HiveSQL不支持触发器(Trigger)。
为什么Hive没有触发器?
-
设计哲学不同:
-
Hive :面向批处理 和离线分析,设计目标是处理TB/PB级数据的复杂查询
-
触发器 :面向实时事件响应,是OLTP(在线事务处理)数据库的特性
-
-
技术架构限制:
-
存储与计算分离 :数据在HDFS/S3,计算在集群,难以实现"数据变更即时触发"
-
无事务支持(早期):触发器需要在事务中执行,Hive传统上不支持ACID事务
-
延迟特性 :Hive查询通常是分钟/小时级,触发器需要毫秒级响应
-
触发器性能开销大,违背批处理设计。
解释一下COLLECT_SET()函数如何使用?
策略2:建立专门的数据质量监控(DQC)
银行数仓通常有独立的数据质量监控平台,定期扫描:
sql
-- 质量检查SQL:找出重复的身份证号
SELECT id_no, COUNT(*) as cnt,
COLLECT_SET(name) as names, -- 收集不同的名字
COLLECT_SET(cust_id) as cust_ids
FROM dim_customer
WHERE id_no IS NOT NULL
GROUP BY id_no
HAVING COUNT(*) > 1
-- 结果会推送到数据质量告警平台,通知负责人处理
关系型数据库中的ACID是什么?
A:原子性(Atomicity)
-
定义 :事务中的所有操作要么全部完成,要么全部不完成,不可能停在中间状态。
-
银行比喻 :转账操作包含两个步骤:1.从A账户扣款 2.向B账户加款。原子性确保这两个步骤要么都成功,要么都失败。绝不会出现A账户钱扣了,但B账户没收到的情况。
-
技术实现 :通过事务日志(Transaction Log) 和回滚(Rollback) 机制实现。
C:一致性(Consistency)
-
定义 :事务执行前后,数据库必须保持一致的状态,所有数据约束(如主键、外键、检查约束)都必须满足。
-
银行比喻 :转账前后,银行的总资产必须保持不变(A账户减少的金额 = B账户增加的金额)。同时,账户余额不能为负数(检查约束)。
-
技术实现:由数据库的完整性约束和应用程序逻辑共同保证。
I:隔离性(Isolation)
-
定义 :多个事务并发执行时,彼此相互隔离,一个事务不应看到其他未完成事务的中间状态。
-
银行比喻 :当你正在查账户余额时,正好有人给你转账。隔离性确保你要么看到转账前的余额,要么看到转账后的完整余额,绝不会看到一个"正在转账中"的中间值(比如只看到对方账户已扣款,但你账户还没入账的状态)。
-
技术实现 :通过锁机制 或多版本并发控制(MVCC) 实现,有不同的隔离级别。
D:持久性(Durability)
-
定义 :一旦事务提交成功,它对数据的修改就是永久性的,即使系统崩溃也不会丢失。
-
银行比喻 :转账成功后,这笔交易记录必须永久保存,即使银行服务器突然断电,重启后转账结果依然有效。
-
技术实现 :通过预写日志(WAL) 和数据持久化存储(磁盘)实现。
一致性中的主键约束、外键约束、检查约束分别是什么?
一、主键约束:数据的"身份证"
核心定义
主键约束(Primary Key Constraint) 是表中唯一标识每一行记录的列或列组合,它必须满足:
-
唯一性:主键值在整个表中必须唯一
-
非空性:主键值不能为NULL
-
不可变性:主键值一旦确定,通常不应更改
二、外键约束:数据的"关系证明"
核心定义
外键约束(Foreign Key Constraint) 是一个表中的字段,它引用另一个表的主键,用于维护表间的引用完整性。
外键的核心规则
-
引用存在:外键值必须在被引用表的主键中存在(或为NULL)
-
数据一致性:防止"孤儿记录"
-
级联操作:可定义当主表数据变化时,从表的联动行为
三、什么是检查约束?
简单定义
检查约束(Check Constraint)是数据库中对单个列或整行数据施加的条件规则,只有满足该条件的数据才能被插入或更新。
实例:账户余额不能为负数
sql
-- 创建账户表时定义检查约束
CREATE TABLE accounts (
account_no VARCHAR(20) PRIMARY KEY,
account_name VARCHAR(100),
balance DECIMAL(15,2) NOT NULL,
-- 检查约束:余额必须 >= 0
CONSTRAINT ck_balance_non_negative
CHECK (balance >= 0),
account_type VARCHAR(10),
-- 检查约束:账户类型只能是特定值
CONSTRAINT ck_account_type
CHECK (account_type IN ('SAVINGS', 'CURRENT', 'FIXED_DEPOSIT', 'LOAN'))
);