那些年我们一起踩过的“坑”:吐槽医疗数据库设计

更新时间:2019-05-09

医院中的各类信息系统,除大数据分析等相关系统以外,都属于典型的OLTP系统(On-Line Transaction Processing,联机事务处理过程)。此类系统需要即时地处理输入的数据,及时地处理返回结果,而且并发操作要求高,大量用户同时查增删改数据,对数据库的性能要求极高。良好的数据库设计可以极大地提升应用系统的性能,而且可以使代码变得简单清晰。如果数据结构清晰了,那么围绕着数据运行的代码自然也就清晰了,应用软件的前台运行流程和运行效率也都能大幅提高。

实际上,医院信息科软件工程师每天最频繁的操作应该是医院各软件的数据库,尤其是HIS的数据库。记得曾经有位主任讲过,不会写SQL语句的工程师,就不是一个合格的信息科工程师。笔者曾经研究过二十几家医疗信息软件开发商设计的数据库,也经常与其他医疗机构的信息中心主任和工程师讨论厂商的数据结构问题。

 这其中,一些大厂商的数据库设计要好一些,但也确实有不少开发商的数据库水平、能力和规范性实在不敢恭维。而且,很多开发商没有专职的DBA和数据库设计人员,一般由开发工程师自行设计数据结构。当出现性能问题时,不从自身数据库设计、逻辑结构和代码质量上找原因,往往一味地要求医院提高服务器存储等硬件配置。比如,把8颗CPU换成16颗,内存128GB换成256GB,存储换成全闪存存储等。用硬件设备的更新升级确实能掩盖数据库设计和软件产品问题,但其实厂商去

优化数据库设计、提高软件代码质量才是解决数据库性能问题的关键所在。

今天就笔者总结的一些软件开发商数据库设计方面的共性和普遍性问题,对软件开发商的的数据库设计进行“吐槽”,并提出解决建议供大家参考。请软件开发商们切勿对号入座,初衷并不是给开发商们揭丑,而是为了大家共同提高医疗信息软件的开发水平和良好生态。(本文主要以医院使用最多的关系型数据库Oracle、SQL Server数据库为例,对于Caché、DB2等其他数据库不在本文讨论范围)

吐槽1:不规范的数据库表命名、字段命名。

实例:某系统的数据表名为T1、T2、T3……,每张数据表的字段名为C1、C2、C3……。

某系统的数据表名和字段名如下图所示:

程序代码诸如:select t1.c8,t2.c2 where t1.c1=t2.c1。

后果:

(1)影响开发效率,工程师需要时刻查对数据字典手册。

(2)SQL代码如同天书一般,极难读懂。

(3)当出现人员离职变动等情况时,后续人员接手困难。

(4)发生问题或错误后,数据极难排错。

(5)医院信息科人员难以接手。

建议:规范表名和字段名的命名规则,望文知意、易懂易用,并形成体系。例如,基础数据字典都以dt_开头,如dt_org、dt_item;患者信息相关表都以pa_开头;住院医嘱相关表都以cmi_ord开头;所有有关日期的字段都以date_开头;所有人员代码有关的字段都以empid_开头。

吐槽2:关键的数据表不是独立主键。

实例:某系统住院患者的主表将住院号和住院次数设置为联合主键。

后果:相关的其他表和各种查询都需要关联住院号与住院次数的双字段双条件,增加复杂度且联合主键联合索引影响执行的速度。

建议:增加流水号,后台用流水号做关联,尽量避免联合主键。

吐槽3:表关系设置不合理导致需要多表复杂关联。

实例:某系统的生成摆药单需要多张表进行关联,且检索出的数据重复,需要加入select distinct去除重复数据,导致执行效率低下。

后果:用distinct去除重复值效率低下。

  建议:合理设置表结构关系,优化SQL语句,尽量避免distinct。

吐槽4:索引设置不合理而导致全表扫描。

实例:某系统退费日期上没有索引。

后果:结账报表特别慢,增加退费日期索引后,速度提升20倍以上。

建议:科学合理地设置索引能起到事半功倍的效果。

吐槽5:重复执行语句未绑定变量导致大量硬解析。

实例:某系统按病区执行某报表,程序语句只是病区编码不同,但未把病区编码作为变量,而是重复一遍遍反复执行。

后果:未绑定变量的重复执行数据库认为都是新的语句,需要使用硬解析,生成不同的执行计划,耗用大量的CPU和内存资源。

建议:尽可能使用绑定变量避免硬解析产生所需的额外的系统资源。

吐槽6:没有设置合理的字典表。

 实例:某系统没有设置挂号号别编码字典表,在挂号排班号表中文本字段表示。

 后果:当进行号别的调整时,需要到挂号排班号表中逐条手工修改。

 建议:科学的定义和设置各种字典数据表。

吐槽7:工程师只关注了结果正确,没有考虑数据大量增长后的问题。

实例:某系统查询未预约的申请单列表没有时间条件。

后果:随着数据量的积累,查询速度越来越慢。

建议:增加时间条件后(默认只查询最近十五天内的未预约申请单),问题马上解决。很多查询都可以增加时间区间的条件。

吐槽8:SQL语句写得有问题。

 实例:如下图

后果:从上图可以看出,代码只差引号,执行结果相同,但执行的效率和消耗相差400倍。

建议:SQL语句逻辑要清晰,要有规范和优化。

吐槽9:不合理的轮询机制压垮数据库。

实例:某系统与HIS的数据接口,每5分钟一次轮询获取数据,且语句写的不好没有时间条件。

后果:此接口一上线,导致HIS全院运行缓慢。

建议:数据接口科学设置,避免不合理的轮询机制。

吐槽10:不提供文档资料或资料不完整。

实例:某系统不告知甲方数据库密码,不提供数据结构材料;某系统虽然提供了数据结构说明,但与实际情况不符,一些新增或者调整的表、视图或字段在数据结构说明中没有体现。

后果:院方对数据库结构不熟悉、不了解,过于依赖软件开发商,不能自行排错或解决问题。

建议:将提供数据库密码和文档要求写入合同和验收条件。

以上10个典型问题只是具有代表性的实例,还有一些诸如高并发下的锁表问题、输入数据完整性缺失问题、表设计得与业务绑定得太紧密造成表的可拓展性和可修改性太差问题、非必要数据冗余量太大问题、缺少必要的字段造成无法跟踪用户操作问题、滥用存储过程和触发器导致查错困难等问题,因篇幅限制,不再一一列举。

记得我的某位大学老师曾讲过,一个优秀的程序开发者从三点可以看出来:一是设计规范逻辑清晰;二是程序注释到位;三是写文档时间比写代码时间还多。我至今都记忆深刻,觉得非常有道理。我在想,以后在考察开发商能力水平时,是否可以把数据库的设计、源代码有没有注释、逻辑结构是不是清晰等列为考察条件。

总而言之,数据库是医院各类应用系统的根基,是软件流畅运行的起点,它起着决定性的质变作用。

我们希望各个医疗机构和软件厂商都能把数据库设计高度重视起来,来共同提升数据库设计和应用能力。