Chinaunix首页 | 论坛 | 博客
  • 博客访问: 309077
  • 博文数量: 40
  • 博客积分: 1
  • 博客等级: 民兵
  • 技术积分: 670
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-31 11:19
个人简介

从事银行核心系统设计开发的程序猿

文章存档

2019年(1)

2018年(4)

2017年(11)

2016年(6)

2015年(18)

分类: 信息化

2015-08-21 02:06:25

*多成员表


    银行核心系统通常生命周期在10年左右,现在随着银行系统的数量和复杂度增加,系统的生命期也有逐渐变长的趋势。通常核心系统上线时,很多数据表的记录数并不太多,而当系统运行年限越来越长,巨型数据表就越来越多。另外,随着城商、农信的省级集中,用以前针对城市级商业银行的系统,来应对省级的数据量,原先规模合理的表,也会变成巨型表。在实际项目中,已经遇到记录数上亿,和十亿级别的表了,不光严重影响系统性能,在7*24小时不间断运行条件下,数据清理都是个难题。以往的系统,在这方面考虑是比较少的,大概是因为系统设计实现者通常只管上线,不会长期维护,而且原先系统面向银行的规模较小。因此,要么没考虑大数据量表的拆分,要么常处理方法也只是简单区分下当前表和历史表,在日终时做个当前倒历史的批量(历史表巨大的话,倒历史时间也会变得很长)。

    分析银行的数据表,容易产生很多记录数的案例,就会发现通常有两种状况比较常见。一种是明细流水性质的表,产生一笔就会新增一条记录,日积月累就会变得很大。这里面大多数都可以用日期时间为顺序和查询依据的,例如账户明细表,传票表等。这类表很明显可以按日期进行划分。超过一定的期限以后,历史的数据就可以清理了,通常历史查询功能由ODS之类的数据仓库系统提供。经过清理后,数据量可以保持稳定。另一种是账户主表,凭证主表,客户信息表等,随着系统多年使用逐渐增长,而且可清理的不多,数据量随业务发展总体呈增长趋势。


    这里我们看看在Firebird系统中巨型表的解决办法。从根本上说,应当将大表分小,并且要适合使用的情景。在开放平台数据库,有分区表的概念,而在400平台,对应的就是*FILE的多MEMBER。对于可按日期划分的表,我们可以带日期为MEMBER名,每日一个MEMBER,预先创建好,无需倒历史切换,解决了7*24小时和数据清理的问题。对于主表,可按主键号码或某些字段hash计算分MEMBER。例如,客户表按客户号的hash分区,凭证表按凭证号的hash分区。但账户表要按账户所属机构号分区,这是为了优化结息批处理性能,利于每个按机构并发的结息程序只访问一个MEMBER。
    400系统对多MEMBER的限制有哪些呢?首先,同一个*FILE支持的MEMBER数量,最大为32767个。按每日分区计算,大约可以支持90年。按hash计算,10亿级别的表hash到100个MEMBER,每个MEMBER仅1000万记录数量。其次,单个MEMBER最多记录数为2^32,大约42亿。但实际上记录数过多,访问操作性能会指数级下降。单个MEMBER内记录数在1000万级别比较合适。最后,对于LF文件的单个MEMBER,能关联PF的MEMBER数量是有限制的,大概是32个,但实际使用中LF的MEMBER命名与PF相同,完全的一对一建立。如果要搜索多个MEMBER,在应用程序中循环读取实现。


    有关多MEMBER的命令有以下这些。
    CRTPF或CHGPF时指定MAXMBRS为*NOMAX。
    CRTLF或CHGLF时指定MAXMBRS为*NOMAX。
    ADDPFM 在PF中新增一个MEMBER。
    ADDLFM 在LF中新增一个MEMBER。
    RMVM 删除一个指定的MEMBER。
    CLRPFM 清空一个MEMBER的所有记录。


    下面的CL程序是给PF和LF增加连续日期的MEMBER例子。MEMBER名类似M20150821。

  1. PGM PARM(&FLNM &STNMC &EDNMC)
  2. INCLUDE SRCMBR(CLHD) SRCFILE(DSCPPGM)
  3. DCL VAR(&FLNM) TYPE(*CHAR) LEN(10)
  4. DCL VAR(&STNMC) TYPE(*CHAR) LEN(8)
  5. DCL VAR(&EDNMC) TYPE(*CHAR) LEN(8)
  6. DCL VAR(&STNM) TYPE(*CHAR) LEN(10)
  7. DCL VAR(&EDNM) TYPE(*CHAR) LEN(10)
  8. DCL VAR(&MBNM) TYPE(*CHAR) LEN(10)
  9. DCL VAR(&DAYS) TYPE(*DEC) LEN(5 0)
  10. DCL VAR(&I) TYPE(*DEC) LEN(5 0)
  11. DCL VAR(&NM) TYPE(*CHAR) LEN(10)
  12. DCL VAR(&FLTP) TYPE(*CHAR) LEN(10)
  13. DCL VAR(&FLLB) TYPE(*CHAR) LEN(10)
  14. DCL VAR(&PFNM) TYPE(*CHAR) LEN(10)
  15. RTVOBJD OBJ(&FLNM) OBJTYPE(*FILE) OBJATR(&FLTP) RTNLIB(&FLLB)
  16. CHGVAR VAR(&STNM) VALUE(&STNMC)
  17. CHGVAR VAR(&EDNM) VALUE(&EDNMC)
  18. CALL PGM(DATECALC) PARM(&STNM &EDNM &DAYS)
  19. IF COND(&DAYS *LT 0) THEN(GOTO CMDLBL(ENDPGM))
  20. CHGVAR VAR(&I) VALUE(0)
  21. ADD: IF COND(&I *LE &DAYS) THEN(DO)
  22. CHGVAR VAR(&NM) VALUE(' ')
  23. CALL PGM(DATECALC) PARM(&STNM &NM &I)
  24. CHGVAR VAR(&MBNM) VALUE('M' *TCAT &NM)
  25. IF COND(&FLTP *EQ 'PF') THEN(DO)
  26. ADDPFM FILE(&FLNM) MBR(&MBNM)
  27. ENDDO
  28. IF COND(&FLTP *EQ 'LF') THEN(DO)
  29. CHGVAR VAR(&PFNM) VALUE(%SST(&FLNM 1 7))
  30. ADDLFM FILE(&FLNM) MBR(&MBNM) DTAMBRS((&FLLB/&PFNM +
  31. (&MBNM)))
  32. ENDDO
  33. CHGVAR VAR(&I) VALUE(&I + 1)
  34. GOTO CMDLBL(ADD)
  35. ENDDO
  36. ENDPGM: ENDPGM



    下面的CL程序是给PF和LF增加连续hash的MEMBER例子。MEMBER名类似M01到M99。另外还有3位数M001到M999的程序就不贴了。

  1. PGM PARM(&FLNM &STNMC &EDNMC)
  2. INCLUDE SRCMBR(CLHD) SRCFILE(DSCPPGM)
  3. DCL VAR(&FLNM) TYPE(*CHAR) LEN(10)
  4. DCL VAR(&STNMC) TYPE(*CHAR) LEN(2)
  5. DCL VAR(&EDNMC) TYPE(*CHAR) LEN(2)
  6. DCL VAR(&STNM) TYPE(*INT)
  7. DCL VAR(&EDNM) TYPE(*INT)
  8. DCL VAR(&MBNM) TYPE(*CHAR) LEN(10)
  9. DCL VAR(&NM) TYPE(*CHAR) LEN(2)
  10. DCL VAR(&FLTP) TYPE(*CHAR) LEN(10)
  11. DCL VAR(&FLLB) TYPE(*CHAR) LEN(10)
  12. DCL VAR(&PFNM) TYPE(*CHAR) LEN(10)
  13. RTVOBJD OBJ(&FLNM) OBJTYPE(*FILE) OBJATR(&FLTP) RTNLIB(&FLLB)
  14. CHGVAR VAR(&STNM) VALUE(&STNMC)
  15. CHGVAR VAR(&EDNM) VALUE(&EDNMC)
  16. ADD: IF COND(&STNM *LE &EDNM) THEN(DO)
  17. CHGVAR VAR(&NM) VALUE(&STNM)
  18. CHGVAR VAR(&MBNM) VALUE('M' *TCAT &NM)
  19. IF COND(&FLTP *EQ 'PF') THEN(DO)
  20. ADDPFM FILE(&FLNM) MBR(&MBNM)
  21. ENDDO
  22. IF COND(&FLTP *EQ 'LF') THEN(DO)
  23. CHGVAR VAR(&PFNM) VALUE(%SST(&FLNM 1 7))
  24. ADDLFM FILE(&FLNM) MBR(&MBNM) DTAMBRS((&FLLB/&PFNM +
  25. (&MBNM)))
  26. ENDDO
  27. CHGVAR VAR(&STNM) VALUE(&STNM + 1)
  28. GOTO CMDLBL(ADD)
  29. ENDDO
  30. ENDPGM



    建立起多MEMBER文件以后,在应用程序中使用就有注意的地方了。
    首要原则,对上层组件尽量透明,把多MEMBER的操作尽可能封装在数据表访问组件内部,对外就像操作的是一个文件一样。这涉及到核心系统整体规划上的“交易--模块公有组件--模块私有组件--数据访问封装”体系,就是另外的话题了。
    那么,在RPG程序中,多MEMBER文件的代码怎么写呢?主要区别在F表定义上。F表定义文件的时候,选项部分需要多写两个,EXTMBR(V_MBRNAME) USROPN。EXTMBR用于根据变量V_MBRNAME的值指示要操作的MEMBER名,USROPN则是在程序执行到OPEN语句时再打开文件。通过程序中先给V_MBRNAME赋值,再执行OPEN语句,就可以操作指定的MEMBER啦。值得注意的是,前面介绍过激活组会保持文件的打开状态以供下次调用使用,多MEMBER时,不能简单通过%OPEN()内置函数来判断文件是否已打开,因为%OPEN()函数对不同MEMBER不作区分,比如已打开M003,这次虽然V_MBRNAME赋值了M998,但%OPEN()判断时仍认为文件已打开,必须要通过打开的MEMBER名是否相同来额外区分。


    RPG对多MEMBER表的使用例子节选如下。

  1. **********************************************************************
  2. FAPLBTTR O E DISK INFSR(#FLEX) INFDS(S_PLBTTR)
  3. F EXTMBR(V_MBRNAME)
  4. F QUALIFIED USROPN COMMIT
  5. **********************************************************************
  6. D*引入数据字典枚举常量
  7. D/COPY DSCPPGM,ENUM
  8. D*引入程序公共结构
  9. D/COPY DSCPPGM,PGDS
  10. D*文件结构定义
  11. DS_PLBTTR DS LIKEDS(FILESDS)
  12. DR_PLBTTR DS LIKEREC(APLBTTR.RAPLBTTR:*OUTPUT)
  13. *************************
  14. D*常量定义
  15. DC_PREMBR C CONST('M')
  16. *************************
  17. **日期结构
  18. DD_DATE DS QUALIFIED
  19. D YEA 4A
  20. D FLG1 1A
  21. D MON 2A
  22. D FLG2 1A
  23. D DAY 2A
  24. *************************
  25. D*临时变量结构
  26. DD_VARS DS
  27. D V_MBRNAME LIKE(DICT.@@FLNM)
  28. **********************************************************************
  29. ** @MAIN程序的主流程
  30. **********************************************************************
  31. C @MAIN BEGSR
  32. C EVAL FILEDSP = %ADDR(S_PLBTTR)
  33. C EVAL D_DATE = %CHAR(BTWTF1.BTWKDT)
  34. C EVAL V_MBRNAME = C_PREMBR + D_DATE.YEA +
  35. C D_DATE.MON + D_DATE.DAY
  36. C*判断已打开的成员不一致则关闭重新打开
  37. C IF FL_MEMBER <> V_MBRNAME
  38. C CLOSE APLBTTR
  39. C ENDIF
  40. C*打开指定成员
  41. C IF NOT %OPEN(APLBTTR)
  42. C OPEN APLBTTR
  43. C ENDIF
  44. C CLEAR R_PLBTTR
  45. C EVAL-CORR R_PLBTTR = BTWTF1
  46. C EVAL R_PLBTTR.STTMSP = %TIMESTAMP()
  47. C EVAL R_PLBTTR.RPSHNU = 0
  48. C EVAL R_PLBTTR.BKEXST = EXST_NOTEX
  49. /FREE
  50. WRITE APLBTTR.RAPLBTTR R_PLBTTR;
  51. /END-FREE
  52. C ENDSR
  53. **********************************************************************



阅读(3530) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~