风哥教程参考DB2官方文档Telecommunications Solutions、Data Partitioning Feature等内容,详细介绍电信业务库在DB2上的设计、数据分区、索引优化、批量处理。更多视频教程www.fgedu.net.cn
目录大纲
Part01-电信业务系统特点
1.1 电信业务特点
电信业务系统具有以下特点:
- 数据量大:用户数、话单数据量巨大
- 写入密集:实时话单、批量处理
- 查询复杂:多维度统计分析
- 时间敏感:实时计费、实时查询
- 历史数据归档:按时间分区归档
- 高可用要求:7×24小时不间断服务
1.2 数据分类
- 用户数据:客户信息、账户信息
- 产品数据:套餐、资费、优惠
- 话单数据:通话、短信、流量详单
- 账单数据:账单、费用明细
- 统计数据:日/周/月统计报表
Part02-表结构设计
2.1 用户表设计
CREATE TABLE CUSTOMER (
CUST_ID VARCHAR(32) NOT NULL,
CUST_NAME VARCHAR(100) NOT NULL,
ID_TYPE VARCHAR(10) NOT NULL,
ID_NO VARCHAR(50) NOT NULL,
CUST_LEVEL VARCHAR(10) NOT NULL,
CUST_STATUS VARCHAR(10) NOT NULL,
REGION_ID VARCHAR(10) NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
UPDATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_CUSTOMER PRIMARY KEY (CUST_ID)
) ORGANIZE BY ROW;
# 账户表
CREATE TABLE ACCOUNT (
ACCT_ID VARCHAR(32) NOT NULL,
CUST_ID VARCHAR(32) NOT NULL,
ACCT_TYPE VARCHAR(10) NOT NULL,
ACCT_STATUS VARCHAR(10) NOT NULL,
BALANCE DECIMAL(18, 2) NOT NULL DEFAULT 0,
CREDIT_LIMIT DECIMAL(18, 2) NOT NULL DEFAULT 0,
CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
UPDATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_ACCOUNT PRIMARY KEY (ACCT_ID)
) ORGANIZE BY ROW;
# 用户产品订购表
CREATE TABLE SUBSCRIPTION (
SUB_ID VARCHAR(32) NOT NULL,
CUST_ID VARCHAR(32) NOT NULL,
ACCT_ID VARCHAR(32) NOT NULL,
PROD_ID VARCHAR(32) NOT NULL,
MSISDN VARCHAR(20) NOT NULL,
SUB_STATUS VARCHAR(10) NOT NULL,
EFF_DATE DATE NOT NULL,
EXP_DATE DATE,
CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
UPDATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_SUBSCRIPTION PRIMARY KEY (SUB_ID)
) ORGANIZE BY ROW;
# 创建索引
CREATE INDEX IDX_SUBSCRIPTION_MSISDN ON SUBSCRIPTION(MSISDN) CLUSTER;
CREATE INDEX IDX_SUBSCRIPTION_CUST ON SUBSCRIPTION(CUST_ID, SUB_STATUS);
CREATE INDEX IDX_SUBSCRIPTION_PROD ON SUBSCRIPTION(PROD_ID);
2.2 话单表设计
CREATE TABLE CDR_VOICE (
CDR_ID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
MSISDN VARCHAR(20) NOT NULL,
OTHER_PARTY VARCHAR(20),
CALL_TYPE VARCHAR(10) NOT NULL,
CALL_TIME TIMESTAMP NOT NULL,
DURATION INTEGER NOT NULL,
ROAMING_TYPE VARCHAR(10),
CHARGE DECIMAL(10, 2) NOT NULL,
REGION_ID VARCHAR(10) NOT NULL,
FILE_NAME VARCHAR(100),
RECORD_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_CDR_VOICE PRIMARY KEY (CDR_ID)
) PARTITION BY RANGE (CALL_TIME)
(
STARTING ‘2026-01-01-00.00.00.000000’
ENDING ‘2026-12-31-23.59.59.999999’
EVERY 1 DAY
);
# 创建索引
CREATE INDEX IDX_CDR_VOICE_MSISDN ON CDR_VOICE(MSISDN, CALL_TIME DESC) PARTITIONED;
CREATE INDEX IDX_CDR_VOICE_TIME ON CDR_VOICE(CALL_TIME) PARTITIONED;
CREATE INDEX IDX_CDR_VOICE_REGION ON CDR_VOICE(REGION_ID, CALL_TIME) PARTITIONED;
# 短信详单表
CREATE TABLE CDR_SMS (
CDR_ID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
MSISDN VARCHAR(20) NOT NULL,
OTHER_PARTY VARCHAR(20),
SMS_TYPE VARCHAR(10) NOT NULL,
SEND_TIME TIMESTAMP NOT NULL,
CHARGE DECIMAL(10, 2) NOT NULL,
REGION_ID VARCHAR(10) NOT NULL,
FILE_NAME VARCHAR(100),
RECORD_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_CDR_SMS PRIMARY KEY (CDR_ID)
) PARTITION BY RANGE (SEND_TIME)
(
STARTING ‘2026-01-01-00.00.00.000000’
ENDING ‘2026-12-31-23.59.59.999999’
EVERY 1 DAY
);
# 流量详单表
CREATE TABLE CDR_DATA (
CDR_ID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
MSISDN VARCHAR(20) NOT NULL,
SESSION_ID VARCHAR(50),
START_TIME TIMESTAMP NOT NULL,
END_TIME TIMESTAMP NOT NULL,
DATA_UP BIGINT NOT NULL,
DATA_DOWN BIGINT NOT NULL,
TOTAL_DATA BIGINT NOT NULL GENERATED ALWAYS AS (DATA_UP + DATA_DOWN),
CHARGE DECIMAL(10, 2) NOT NULL,
REGION_ID VARCHAR(10) NOT NULL,
FILE_NAME VARCHAR(100),
RECORD_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_CDR_DATA PRIMARY KEY (CDR_ID)
) PARTITION BY RANGE (START_TIME)
(
STARTING ‘2026-01-01-00.00.00.000000’
ENDING ‘2026-12-31-23.59.59.999999’
EVERY 1 DAY
);
2.3 账单表设计
CREATE TABLE BILL (
BILL_ID VARCHAR(32) NOT NULL,
ACCT_ID VARCHAR(32) NOT NULL,
CUST_ID VARCHAR(32) NOT NULL,
BILL_CYCLE VARCHAR(6) NOT NULL,
TOTAL_CHARGE DECIMAL(18, 2) NOT NULL,
DISCOUNT_AMOUNT DECIMAL(18, 2) NOT NULL DEFAULT 0,
ACTUAL_CHARGE DECIMAL(18, 2) NOT NULL,
PAID_AMOUNT DECIMAL(18, 2) NOT NULL DEFAULT 0,
BILL_STATUS VARCHAR(10) NOT NULL,
BILL_DATE DATE NOT NULL,
DUE_DATE DATE NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
UPDATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_BILL PRIMARY KEY (BILL_ID)
) PARTITION BY RANGE (BILL_CYCLE)
(
STARTING ‘202601’ ENDING ‘202612’ EVERY 1 MONTH
);
# 账单明细表
CREATE TABLE BILL_DETAIL (
DETAIL_ID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
BILL_ID VARCHAR(32) NOT NULL,
CHARGE_TYPE VARCHAR(20) NOT NULL,
CHARGE_NAME VARCHAR(100) NOT NULL,
CHARGE_AMOUNT DECIMAL(18, 2) NOT NULL,
DISCOUNT_AMOUNT DECIMAL(18, 2) NOT NULL DEFAULT 0,
ACTUAL_AMOUNT DECIMAL(18, 2) NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_BILL_DETAIL PRIMARY KEY (DETAIL_ID)
) PARTITION BY REFERENCE (FK_BILL_DETAIL_BILL);
# 创建索引
CREATE INDEX IDX_BILL_ACCT_CYCLE ON BILL(ACCT_ID, BILL_CYCLE) PARTITIONED;
CREATE INDEX IDX_BILL_CUST_CYCLE ON BILL(CUST_ID, BILL_CYCLE) PARTITIONED;
CREATE INDEX IDX_BILL_STATUS ON BILL(BILL_STATUS, BILL_CYCLE) PARTITIONED;
Part03-分区与分表
3.1 范围分区表管理
SELECT
TABSCHEMA,
TABNAME,
DATAPARTITIONNAME,
DATAPARTITIONID,
LOWVALUE,
HIGHVALUE
FROM SYSCAT.DATAPARTITIONS
WHERE TABNAME = ‘CDR_VOICE’
ORDER BY DATAPARTITIONID;
# 添加新分区
ALTER TABLE CDR_VOICE ADD PARTITION
STARTING ‘2027-01-01-00.00.00.000000’
ENDING ‘2027-01-31-23.59.59.999999’;
# 分离旧分区
ALTER TABLE CDR_VOICE DETACH PARTITION PART0 INTO TABLE CDR_VOICE_ARCHIVE_PART0;
# 附加分区
ALTER TABLE CDR_VOICE ATTACH PARTITION
STARTING ‘2026-01-01-00.00.00.000000’
ENDING ‘2026-01-31-23.59.59.999999’
FROM TABLE CDR_VOICE_ARCHIVE_PART0;
# 删除旧分区
ALTER TABLE CDR_VOICE DROP PARTITION PART0;
# 重组表
REORG TABLE CDR_VOICE;
RUNSTATS ON TABLE CDR_VOICE AND INDEXES ALL;
3.2 MDC多维聚簇表
CREATE TABLE CDR_VOICE_MDC (
CDR_ID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
MSISDN VARCHAR(20) NOT NULL,
CALL_TYPE VARCHAR(10) NOT NULL,
CALL_DATE DATE NOT NULL,
CALL_TIME TIMESTAMP NOT NULL,
DURATION INTEGER NOT NULL,
CHARGE DECIMAL(10, 2) NOT NULL,
REGION_ID VARCHAR(10) NOT NULL,
CONSTRAINT PK_CDR_VOICE_MDC PRIMARY KEY (CDR_ID)
) ORGANIZE BY DIMENSIONS (
(MSISDN),
(CALL_DATE),
(REGION_ID)
);
# 查看MDC信息
SELECT
TABSCHEMA,
TABNAME,
COLNAME,
DIMENSION
FROM SYSCAT.MDCDIMENSIONS
WHERE TABNAME = ‘CDR_VOICE_MDC’;
# 分析MDC块使用情况
SELECT
TABSCHEMA,
TABNAME,
TOTAL_BLOCKS,
EMPTY_BLOCKS,
USED_BLOCKS,
BLOCK_INDEX_ENTRIES
FROM TABLE(MON_GET_MDC_BLOCK_STATS(NULL, NULL, -2)) AS T;
Part04-批量处理与性能优化
4.1 话单批量导入
LOAD FROM /data/cdr/voice_20260408.del OF DEL
MODIFIED BY COLDEL, CHARDEL” DATEFORMAT=”YYYY-MM-DD” TIMEFORMAT=”HH:MM:SS”
INSERT INTO CDR_VOICE (MSISDN, OTHER_PARTY, CALL_TYPE, CALL_TIME, DURATION, ROAMING_TYPE, CHARGE, REGION_ID, FILE_NAME)
STATISTICS YES WITH DISTRIBUTION AND DETAILED INDEXES ALL
NONRECOVERABLE;
# 使用IMPORT导入
IMPORT FROM /data/cdr/voice_20260408.del OF DEL
MODIFIED BY COLDEL, CHARDEL”
COMMITCOUNT 10000
INSERT INTO CDR_VOICE;
# db2move批量导入
db2move fgedb load -sn fgedu -tn CDR_VOICE -l /data/load -u db2inst1 -p password;
# 使用存储过程批量插入
CREATE OR REPLACE PROCEDURE SP_BATCH_INSERT_CDR(
IN p_start_date DATE,
IN p_end_date DATE,
OUT p_total_count INTEGER,
OUT p_result_code VARCHAR(10),
OUT p_result_msg VARCHAR(200)
)
LANGUAGE SQL
BEGIN
DECLARE v_count INTEGER DEFAULT 0;
SET p_result_code = ‘SUCCESS’;
SET p_result_msg = ‘批量插入成功’;
INSERT INTO CDR_VOICE (MSISDN, OTHER_PARTY, CALL_TYPE, CALL_TIME, DURATION, CHARGE, REGION_ID)
SELECT
MSISDN,
OTHER_PARTY,
CALL_TYPE,
CALL_TIME,
DURATION,
CHARGE,
REGION_ID
FROM CDR_VOICE_STAGING
WHERE CALL_DATE BETWEEN p_start_date AND p_end_date;
GET DIAGNOSTICS v_count = ROW_COUNT;
SET p_total_count = v_count;
END;
4.2 批量计费处理
CREATE OR REPLACE PROCEDURE SP_RATING(
IN p_bill_cycle VARCHAR(6),
OUT p_total_calls INTEGER,
OUT p_total_charge DECIMAL(18, 2),
OUT p_result_code VARCHAR(10),
OUT p_result_msg VARCHAR(200)
)
LANGUAGE SQL
BEGIN
DECLARE v_start_date DATE;
DECLARE v_end_date DATE;
SET p_result_code = ‘SUCCESS’;
SET p_result_msg = ‘计费成功’;
SET v_start_date = TO_DATE(p_bill_cycle || ’01’, ‘YYYYMMDD’);
SET v_end_date = LAST_DAY(v_start_date);
INSERT INTO BILL_DETAIL (BILL_ID, CHARGE_TYPE, CHARGE_NAME, CHARGE_AMOUNT, ACTUAL_AMOUNT)
SELECT
b.BILL_ID,
‘VOICE’,
‘通话费用’,
SUM(c.CHARGE),
SUM(c.CHARGE)
FROM CDR_VOICE c
INNER JOIN SUBSCRIPTION s ON c.MSISDN = s.MSISDN
INNER JOIN ACCOUNT a ON s.ACCT_ID = a.ACCT_ID
INNER JOIN BILL b ON a.ACCT_ID = b.ACCT_ID AND b.BILL_CYCLE = p_bill_cycle
WHERE c.CALL_TIME BETWEEN v_start_date AND (v_end_date + 1 DAY – 1 MICROSECOND)
GROUP BY b.BILL_ID;
GET DIAGNOSTICS p_total_calls = ROW_COUNT;
SELECT SUM(CHARGE_AMOUNT) INTO p_total_charge
FROM BILL_DETAIL
WHERE BILL_ID IN (
SELECT BILL_ID FROM BILL WHERE BILL_CYCLE = p_bill_cycle
);
END;
# 调用计费存储过程
CALL SP_RATING(‘202604’, ?, ?, ?, ?);
4.3 性能优化参数
UPDATE DATABASE CONFIGURATION FOR fgedb USING
DATABASE_MEMORY AUTOMATIC
SELF_TUNING_MEM ON
BUFFPAGE -1
PCKCACHESZ -1
CATALOGCACHE_SZ -1
LOGBUFSZ 1024
LOGFILSIZ 2048
LOGPRIMARY 20
LOGSECOND 100
SOFTMAX 100
CHNGPGS_THRESH 30
MINCOMMIT 1
LOCKLIST 20000
MAXLOCKS 50
LOCKTIMEOUT 60
DLCHKTIME 5000;
# DB2注册表变量
db2set DB2_PARALLEL_IO=*
db2set DB2_USE_ALTERNATE_PAGE_CLEANING=ON
db2set DB2_SKIPINSERTED=ON
db2set DB2_EVALUNCOMMITTED=ON
db2set DB2_SKIPDELETED=ON
db2set DB2_INLIST_TO_NLJN=YES
db2set DB2_REDUCED_OPTIMIZATION=YES;
# LOAD优化
db2set DB2_LOAD_COPY_NO_OVERRIDE=COPY YES
db2set DB2_LOAD_READ_AHEAD=AUTOMATIC
db2set DB2_SORT_HEAP_SIZE=AUTOMATIC;
Part05-风哥经验总结与分享
5.1 电信库设计要点
- 按时间分区话单表,便于归档
- 使用MDC表优化常用查询
- 合理设计索引,避免过度索引
- 批量操作使用LOAD而非INSERT
- 合理配置日志参数,支持高吞吐
- 历史数据定期归档和清理
- 使用分区表提高查询效率
5.2 批量处理优化
| 操作类型 | 优化建议 |
|---|---|
| 话单导入 | 使用LOAD,设置NONRECOVERABLE |
| 批量更新 | 分批提交,避免长事务 |
| 批量删除 | 使用分区分离,或分批删除 |
| 统计报表 | 预计算汇总表,物化查询表 |
5.3 运维要点
- 监控分区使用情况,及时添加新分区
- 定期RUNSTATS和REORG
- 监控表空间使用率
- 建立数据归档流程
- 定期备份分区表
- 监控批量作业执行情况
- 建立性能基线,定期对比
学习交流加群风哥微信: itpux-com
风哥Oracle/MySQL/PostgreSQL/Greenplum/DB2/Redis等数据库培训课程,10年一线实战经验,企业级培训,真正掌握数据库核心技术!
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
