达梦数据库体系结构如图1-1所示,由物理存储结构和数据库实例组成。其中,物理存储结构包括存储在磁盘上的数据文件、配置文件、控制文件、日志文件、归档文件等,数据库实例包括内存结构与后台进程。
在达梦数据库中,数据的存储结构区分为物理存储结构和逻辑存储结构两种。物理存储结构主要用于描述数据库外部数据的存储,即在操作系统中如何组织和管理数据,与具体的操作系统有关;逻辑存储结构主要描述数据库内部数据的组织和管理方式,与操作系统没有关系。物理存储结构是逻辑存储结构在物理上的、可见的、可操作的、具体的体现形式。
图1-1 达梦数据库体系结构
物理存储结构描述了达梦数据库中的数据在操作系统中的组织和管理。典型的物理存储结构包括:用于进行功能设置的配置文件;用于记录文件分布的控制文件;用于保存用户实际数据的数据文件、REDO日志文件、归档日志文件、备份文件;用来进行问题跟踪的跟踪日志文件等,如图1-2所示。
图1-2 达梦数据库物理存储结构
1.配置文件
配置文件是达梦数据库用来设置功能选项的一些文本文件的集合。配置文件以.ini为后缀,具有固定的格式,用户可以通过修改其中的某些参数取值实现特定功能项的启用和禁用,并针对当前系统运行环境设置更优的参数值以提升系统性能。
2.控制文件
每个达梦数据库都有一个名为dm.ctl的控制文件。控制文件是一个二进制文件,记录了数据库必要的初始信息,其中主要包括:
(1)数据库名称;
(2)数据库服务器模式;
(3)数据库服务器版本;
(4)数据文件版本;
(5)表空间信息,包括表空间名、表空间物理文件路径等,记录了所有数据库中使用的表空间,并以数组的方式保存起来;
(6)控制文件校验码,校验码由数据库服务器在每次修改控制文件后计算生成,保证控制文件的合法性,防止文件被损坏及被手动修改。
3.数据文件
数据文件以.dbf为后缀,是数据库中最重要的文件类型。一个DM数据文件对应磁盘上的一个物理文件,数据文件是真实数据存储的地方,每个数据库至少有一个与之相关的数据文件。在实际应用中,数据库中通常有多个数据文件。
当达梦数据库的数据文件空间用完时,它可以自动扩展,但可以在创建数据文件时通过MAXSIZE参数限制其扩展量,当然也可以不限制。但是,数据文件的大小最终会受物理磁盘大小的限制。在实际使用时,一般不建议使用单个巨大的数据文件,为一个表空间创建多个较小的数据文件是更好的选择。
数据文件中还有两类特殊的文件:ROLL文件和TEMP文件。ROLL文件用于保存系统的回滚记录,提供事务在回滚时的信息。每个事务的回滚页在回滚段中各自挂链,页内则顺序存放回滚记录。TEMP文件是临时数据文件,主要用于存放临时结果集,用户创建的临时表也存储在TEMP文件中。
4.REDO日志文件
REDO日志文件以.log为后缀。无论何时,在达梦数据库中添加、删除、修改对象,或者改变数据,都会将 REDO 日志写入当前的 REDO 日志文件中。每个达梦数据库实例至少要有两个 REDO 日志文件,默认两个 REDO 日志文件为 DAMENG01.log、DAMENG02.log,这两个REDO日志文件循环使用。
在理想情况下,数据库系统不会用到REDO日志文件中的信息。然而现实世界总是充满了各种意外,例如,电源故障、系统故障、介质故障,或者数据库实例进程被强制终止等,当出现以上情况时,数据库缓冲区中的数据页会来不及写入数据文件。这样,在重启达梦数据库实例时,通过REDO日志文件中的信息,就可以将数据库的状态恢复到发生意外时的状态。REDO日志文件对于数据库是至关重要的。它们用于存储数据库的事务日志,以便系统在出现系统故障和介质故障时能够进行故障恢复。在达梦数据库运行过程中,任何修改数据库的操作都会产生REDO日志。例如,当一条元组插入一个表的时候,插入的结果写入REDO日志;当删除一条元组时,删除该元组的事实也被写入REDO日志,这样,当系统发生故障时,通过分析日志就可以知道在故障发生前系统做了哪些动作,并可以重做这些动作使系统恢复到发生故障之前的状态。
日志文件分为联机日志文件和归档日志文件。以上所说的REDO日志文件都是联机日志文件。在归档模式下,REDO日志文件会被连续复制到归档日志文件中,这就生成了归档日志文件。联机日志文件指的是系统当前正在使用的日志文件,在创建数据库时,联机日志文件通常被扩展至一定长度,其内容则被初始化为空;当系统运行时,联机日志文件逐渐被产生的日志所填充,对联机日志文件的写入是顺序连续的。然而,系统磁盘空间总是有限的,系统必须能够循环利用联机日志文件空间,为了做到这一点,当所有联机日志文件空间被占满时,系统需要清空一部分日志以便重用日志文件空间。为了保证被清空的日志所“保护”的数据在磁盘上是安全的,需要引入一个关键的数据库概念——检查点。当产生检查点时,系统将系统缓冲区中的日志和脏数据页都写入磁盘,以保证当前日志所“保护”的数据页都已安全写入磁盘,这样日志文件就可以被安全重用。
5.归档日志文件
归档日志文件以归档时间命名,后缀也是.log。达梦数据库可以在归档模式和非归档模式下运行。但是,只有当达梦数据库在归档模式下运行时,其在重做联机日志文件时才能生成归档日志文件。
采用归档模式会对系统的性能产生影响,然而系统在归档模式下运行会更安全。当系统发生故障时其丢失数据的可能性更小,这是因为系统一旦发生介质故障,如磁盘损坏,利用归档日志文件系统可以被恢复至发生故障前一刻,也可以还原到指定的时间点,而如果没有归档日志文件,则只能利用备份进行系统恢复。
归档日志文件还是数据守护功能的核心,数据守护中的备机就是通过REDO日志文件来完成与主机数据同步的。
6.逻辑日志文件
如果在达梦数据库上配置了复制功能,复制源就会产生逻辑日志文件。逻辑日志文件是一个流式的文件,有自己的格式,并且不在页、簇和段的管理之下。
逻辑日志文件内部存储按照复制记录的格式,一条记录紧接着一条记录,存储复制源端的各种逻辑操作,用于发送给复制目的端。
7.备份文件
备份文件以.bak为后缀,当系统正常运行时,备份文件不会发挥任何作用。备份文件也不是数据库必须有的联机文件类型之一。然而,从来没有哪个数据库系统能够保证永远正确无误地运行,当数据库出现故障时,备份文件就显得尤为重要了。
当客户利用管理工具或直接发出备份的SQL命令时,DM Server会自动进行备份,并产生一个或多个备份文件,备份文件自身包含了备份的名称、对应的数据库、备份类型和备份时间等信息。同时,系统还会自动记录备份信息及该备份文件所处的位置,但这种记录是松散的,用户可根据需要将其复制至任何地方,并不会影响系统的运行。
8.跟踪日志文件
用户在dm.ini中配置SVR_LOG和SVR_LOG_SWITCH_COUNT参数后就会打开跟踪日志文件。跟踪日志文件是一个纯文本文件,以“dm_commit_日期_时间”命名,在 DM安装目录的log子目录下生成,其内容包含系统各会话执行的SQL语句、参数信息、错误信息等。跟踪日志文件主要用于分析错误和性能问题,基于跟踪日志文件可以对系统运行状态进行分析,例如,可以挑出系统当前执行速度较慢的SQL语句,进而对其进行优化。
打开跟踪日志文件会对系统的性能有较大影响,一般在查错和调优的时候才会打开,在默认情况下系统是关闭跟踪日志文件的。
9.事件日志文件
达梦数据库系统在运行过程中,会在log子目录下产生一个“dm_实例名_日期”命名的事件日志文件。事件日志文件对达梦数据库运行的关键事件进行记录,如系统启动、系统关闭、内存申请失败、I/O错误等致命错误。事件日志文件主要用于系统在出现严重错误时查看并定位产生错误的问题。事件日志文件随着达梦数据库服务的运行一直存在。
10.数据重演文件
调用系统存储过程 SP_START_CAPTURE 和 SP_STOP_CAPTURE,可以获得数据重演文件。数据重演文件用于数据重演,存储了从抓取开始到抓取结束时达梦数据库与客户端的通信消息。使用数据重演文件,可以多次重复抓取这段时间内的数据库系统操作,为系统调试和性能调优提供了一种分析手段。
达梦数据库的逻辑存储结构描述了数据库内部数据的组织和管理方式。达梦数据库为数据库中的所有对象分配逻辑空间,并存放在数据文件中。在达梦数据库内部,所有的数据文件组合在一起被划分到一个或多个表空间中,所有的数据库内部对象都存放在这些表空间中。同时,表空间被进一步划分为段、簇和页(也称为块)。这种细分可以使达梦数据库更加高效地控制磁盘空间的利用率。图1-3显示了逻辑存储结构之间的关系。
可以看出,在DM8中存储的层次结构可以表述为:系统由一个或多个表空间组成;每个表空间都由一个或多个数据文件组成;每个数据文件都由一个或多个簇组成;段是簇的上级逻辑单元,一个段可以跨多个数据文件;簇由磁盘上连续的页组成,一个簇总是在一个数据文件中;页是数据库中最小的分配单元,也是数据库中使用的最小的I/O单元。
1.表空间
在达梦数据库中,表空间由一个或多个数据文件组成。达梦数据库中的所有对象在逻辑上都存放在表空间中,而在物理上都存储在所属表空间的数据文件中。
在创建达梦数据库时,会自动创建 5 个表空间:SYSTEM 表空间、ROLL 表空间、MAIN表空间、TEMP表空间和HMAIN表空间。
图1-3 逻辑存储结构关系示意图
(1)SYSTEM表空间存放了有关达梦数据库的字典信息。
(2)ROLL表空间完全由达梦数据库自动维护,用户无须干预。该表空间用来存放事务运行过程中执行DML 操作之前的值,从而为访问该表空间的其他用户提供表空间数据的读一致性视图。
(3)MAIN 表空间在初始化达梦数据库的时候,会自动创建一个大小为128MB的数据文件MAIN.DBF。在创建用户时,如果没有指定默认表空间,则系统自动指定MAIN表空间为用户默认表空间。
(4)TEMP表空间完全由达梦数据库自动维护。当用户的SQL语句需要利用磁盘空间来完成某个操作时,达梦数据库会从 TEMP 表空间中分配临时段,如创建索引、无法在内存中完成的排序操作、SQL语句中间结果集及用户创建的临时表等都会用到TEMP表空间。
(5)HMAIN表空间属于HTS表空间,完全由达梦数据库自动维护,用户无须干涉。用户在创建 HFS 表空间时,在未指定 HTS 表空间的情况下,HMAIN 表空间充当默认HTS表空间。
每个用户都有一个默认的表空间。SYSSSO、SYSAUDITOR系统用户默认的表空间是SYSTEM表空间,SYSDBA用户默认的表空间为MAIN表空间,新创建的用户如果没有指定默认的表空间,则系统自动指定MAIN表空间为用户默认的表空间。用户在创建表的时候,当指定了存储表空间A,但和当前用户的默认表空间B不一致时,表存储在用户指定的表空间 A 中,并且在默认情况下,在这张表上建立的索引也将存储在表空间 A 中,但是用户默认的表空间是不变的,仍为表空间B。在一般情况下,建议用户自己创建一个表空间来存放业务数据,或者将数据存放在用户默认的表空间MAIN表空间中,而不是将数据存放在SYSTEM表空间中。
2.页
数据页(也称为数据块)是达梦数据库中最小的数据存储单元。页的大小对应物理存储空间上特定数量的存储字节,在达梦数据库中,页的大小可以为 4KB、8KB、16KB 或32KB,用户在创建数据库时可以指定页的大小,默认大小为8KB。一旦创建好了数据库,则在该数据库的整个生命周期内,页的大小都不能改变。图1-4显示了达梦数据库页的典型格式。
图1-4 达梦数据库页的典型格式
页头控制信息包含页类型、页地址等信息。页的中部存放了数据,为了更好地利用数据页,在数据页的尾部专门留出一部分空间用于存放行偏移数组。行偏移数组用于标识页上的空间占用情况,以便管理数据页自身的空间。
在绝大多数情况下,用户无须干预达梦数据库对数据页的管理。但是,达梦数据库还是提供了选项供用户选择,可以在某些情况下为用户提供更佳的数据处理性能。
FILLFACTOR是达梦数据库提供的一个与性能有关的数据页级存储参数,它指定一个数据页在初始化后插入数据时可以使用空间的最大百分比(100),该值在创建表/索引时可以指定。
设置FILLFACTOR参数的值,是为了指定数据页中可用空间百分比(FILLFACTOR)和可扩展空间百分比(100-FILLFACTOR)。可用空间用来执行更多的 INSERT 操作;可扩展空间用来为数据页保留一定的空间,以避免在今后的更新操作中增加列或修改变长列的长度时,引起数据页的频繁分裂。当插入的数据占据的数据页空间百分比小于FILLFACTOR时,允许数据插入该页;否则,将当前数据页中的数据分为两部分,一部分保留在当前数据页中,另一部分存入一个新数据页中。
对于DBA来说,在使用FILLFACTOR时应该在空间和性能之间进行权衡。为了充分利用空间,用户可以设置一个很大的FILLFACTOR值,如100,但是这可能会导致在后续更新数据时频繁引起数据页分裂,而导致需要大量的I/O操作。为了提高更新数据的性能,可以设置一个相对较小(但不是过小)的FILLFACTOR值,使得后续在执行更新操作时,可以尽量避免数据页分裂,提升I/O性能,但这是以牺牲空间利用率换取的性能提高。
3.簇
簇是数据页的上级逻辑单元,由同一个数据文件中16个或32个连续的数据页组成。在达梦数据库中,簇的大小由用户在创建数据库时指定,默认大小为16。假定某个数据文件大小为 32MB,页大小为 8KB,则共有 32MB/8KB/16=256 个簇,每个簇的大小均为8KB×16=128KB。和数据页的大小一样,一旦创建好数据库,此后该数据库簇的大小就不能改变了。
(1)分配数据簇。
当创建一个表/索引的时候,达梦数据库为表/索引的数据段分配至少一个簇,同时数据库会自动生成对应数量的空闲数据页,供后续操作使用。如果初始分配的簇中所有数据页都已经用完,或者新插入/更新数据需要更多的空间,达梦数据库将自动分配新的簇。在默认情况下,达梦数据库在创建表/索引时,初始分配1个簇,当初始分配的空间用完后,达梦数据库会自动扩展。
达梦数据库的表空间在为新的簇分配空闲空间时,首先在表空间中按文件从小到大的顺序在各个数据文件中查找可用的空闲簇,找到后进行分配;如果各数据文件中都没有空闲簇,则在各数据文件中查找足够的空闲空间,将需要的空间先进行格式化,然后进行分配;如果各数据文件的空闲空间也不够,则选择一个数据文件进行扩展。
(2)释放数据簇。
对于用户数据表空间,用户在将一个数据段对应的表/索引对象 DROP 之前,该表对应的数据段会保留至少1个簇不被回收到表空间中。在删除表/索引对象中的记录时,达梦数据库通过修改数据文件中的位图来释放簇,释放后的簇被视为空闲簇,可以供其他对象使用。当用户删除了表中的所有记录时,达梦数据库仍然会为该表保留1个或2个簇供后续使用。若用户使用DROP 语句来删除表/索引对象,则此表/索引对应的段及段中包含的簇全部收回,并供存储于此表空间中的其他模式对象使用。
对于TEMP表空间,达梦数据库会自动释放在执行SQL过程中产生的临时段,并将属于此临时段的簇空间还给TEMP表空间。需要注意的是,TEMP表空间文件在磁盘中所占大小并不会因此而缩减,用户可以通过系统函数SF_RESET_TEMP_TS来进行磁盘空间的清理。
对于ROLL表空间,达梦数据库将定期检查回滚段,并确定是否需要从回滚段中释放1个或多个簇。
4.段
段是簇的上级逻辑分区单元,段由一组簇组成。在同一个表空间中,段可以包含来自不同文件的簇,即一个段可以跨越不同的文件,而一个簇及该簇所包含的数据页则只能来自同一个文件,是连续的16个或32个数据页。由于簇的数量是按需分配的,因此数据段中的不同簇在磁盘上不一定连续。
(1)数据段。
段可以被定义成特定对象的数据结构,如表数据段或索引数据段。表中的数据以表数据段结构存储,索引中的数据以索引数据段结构存储。达梦数据库以簇为单位给每个数据段分配空间,在数据段的簇空间用完后,达梦数据库会给该段重新分配簇,段的分配和释放完全由达梦数据库自动完成,可以在创建表/索引时设置存储参数来决定数据段的簇如何分配。
当用户使用CREATE语句创建表/索引时,达梦数据库会创建相应的数据段。表/索引的存储参数用来决定对应数据段的簇如何分配,这些参数将影响与对象相关的数据段的存储与访问效率。对于分区表,每个分区使用单独的数据段来容纳所有数据;对于分区表上的非分区索引,使用一个索引数据段来容纳所有数据;而对于分区表上的分区索引,每个分区使用一个单独的索引数据段来容纳所有数据。表的数据段及与其相关的索引段不一定要存储在同一个表空间中,用户可以在创建表/索引时,指定不同的表空间存储参数。
(2)临时段。
在达梦数据库中,所有的临时段都创建在 TEMP 表空间中。这样可以分流磁盘设备的I/O,也可以减少由于在SYSTEM表空间或其他表空间中频繁创建临时数据段而造成的碎片。
在处理一个查询操作时,通常需要为 SQL 语句的解析与执行的中间结果准备临时空间。达梦数据库会自动地分配临时段的磁盘空间。例如,达梦数据库在进行排序操作时就可能需要使用临时段,当排序操作可以在内存中执行,或者设法利用索引就可以执行时,就不必创建临时段了。对于TEMP表空间及其索引,达梦数据库也会为它们分配临时段。临时段的分配和释放完全由系统自动控制,用户不能手动进行干预。
(3)回滚段。
达梦数据库在ROLL表空间的回滚段中保存了用于恢复数据库操作的信息。对于未提交事务,当执行回滚语句时,回滚记录被用来进行回滚变更。在数据库恢复阶段,回滚记录被用来进行任何未提交变更的回滚。在多个并发事务运行期间,回滚段还为用户提供数据读一致性,所有正在读取受影响行的用户将不会看到行中的任何变动,直到事务提交后发出新的查询。达梦数据库提供了全自动回滚管理机制来管理回滚信息和ROLL表空间,全自动回滚管理消除了管理回滚段的复杂性。此外,系统将尽可能保存回滚信息,以满足用户查询回滚信息的需要。事务被提交后,回滚数据不能再回滚或恢复,但是从数据读一致性的角度出发,长时间进行查询可能需要这些早期的回滚信息生成早期的数据页镜像,基于此,达梦数据库需要尽可能长时间地保存回滚信息。达梦数据库会收集回滚信息的使用情况,并根据统计结果对回滚信息的保存周期进行调整,数据库将回滚信息的保存周期设置为比系统中活动的最长查询时间稍长一些。
达梦数据库实例一般由一个正在运行的DM后台进程(包含多个线程)及一个大型的共享内存组成。简单来说,实例就是操作达梦数据库的一种手段,是用来访问数据库的内存结构及后台进程的集合。
达梦数据库存储在服务器的磁盘上,而达梦数据库实例存储在服务器的内存中。通过运行达梦数据库实例,可以操作达梦数据库中的内容。在任何时候,一个实例只能与一个数据库进行关联(装载、打开或挂起数据库)。在大多数情况下,一个数据库也只有一个实例对其进行操作。但是,在达梦数据库提供的高性能集群中,多个达梦数据库实例可以同时装载并打开一个数据库(位于一组由多台服务器共享的物理磁盘上),此时,可以同时从多台计算机上访问这个数据库。
1.DM后台进程
DM服务器使用“对称服务器构架”的单进程、多线程结构。这种“对称服务器构架”在有效地利用系统资源的同时,提供了较高的可伸缩性能,这里的线程即操作系统的线程。服务器在运行时由各种内存数据结构和一系列线程组成,线程分为多种类型,不同类型的线程完成不同的任务。线程通过一定的同步机制对数据结构进行并发访问和处理,以完成用户提交的各种任务。达梦数据库服务器是共享的服务器,允许多个用户连接到同一个服务器上,服务器进程称为共享服务器进程。DM后台进程中主要包括监听线程、工作线程、输入输出(I/O)线程、调度线程、日志线程等。
1)监听线程
监听线程的主要任务是在服务器端口上进行循环监听,一旦有来自客户的连接请求,监听线程被唤醒并生成一个会话申请任务,加入工作线程的任务队列,等待工作线程进行处理。监听线程在系统启动完成后才启动,在系统关闭时首先被关闭。为了保证在处理大量客户连接时系统具有较短的响应时间,监听线程比普通线程优先级更高。
2)工作线程
工作线程是DM服务器的核心线程,它从任务队列中取出任务,并根据任务的类型进行相应的处理,负责所有实际数据的相关操作。DM8的初始工作线程个数由配置文件指定,随着会话连接的增加,工作线程也会同步增加,以保持每个会话都有专门的工作线程处理请求。为了保证用户的所有请求及时响应,一个会话上的任务全部由同一个工作线程完成,这样减少了线程切换的代价,提高了系统效率。当会话连接超过预设的阈值时,工作线程数量不再增加,转而由会话轮询线程接收所有用户请求,并加入任务队列,等工作线程空闲时,从任务队列中依次摘取请求任务处理。
3)输入输出(I/O)线程
在数据库活动中,I/O 操作历来都是最耗时的操作之一。当事务需要的数据页不在缓冲区中时,如果在工作线程中直接对那些数据页进行读写,会使系统性能变得非常糟糕,而把I/O操作从工作线程中分离出来是非常明智的做法。I/O线程的职责就是处理这些I/O操作。在通常情况下,DM Server需要进行I/O操作的时机主要有以下3种。
(1)需要处理的数据页不在缓冲区中,此时需要将相关数据页读入缓冲区。
(2)当缓冲区满或系统关闭时,需要将部分脏数据页写入磁盘。
(3)当检查点到来时,需要将所有脏数据页写入磁盘。
I/O 线程在启动后,通常处于睡眠状态,当系统需要进行 I/O 操作时,只需要发出一个I/O请求,I/O线程就会被唤醒以处理该请求,并在完成该I/O操作后继续进入睡眠状态。
I/O线程的个数是可配置的,可以通过设置dm.ini文件中的IO_THR_GROUPS参数来设置,在默认情况下,I/O线程的个数是两个。同时,I/O线程处理I/O请求的策略根据操作系统平台的不同会有很大差别,在一般情况下,I/O线程使用异步的I/O操作将数据页写入磁盘,此时,系统将所有的I/O请求直接递交给操作系统,操作系统在完成这些请求后才通知I/O线程,这种异步I/O的方式使得I/O线程需要直接处理的任务很简单,即完成I/O操作后的一些收尾处理并发出 I/O 操作完成通知;如果操作系统不支持异步 I/O 操作,此时I/O线程需要完成实际的I/O操作。
4)调度线程
调度线程用于接管系统中所有需要定时调度的任务。调度线程每秒轮询一次,负责的任务如下。
(1)检查系统级的时间触发器,若满足触发条件则生成任务加到工作线程的任务队列中由工作线程执行。
(2)清理SQL缓存、计划缓存中失效的缓存项,或者超出缓存限制后淘汰不常用的缓存项。
(3)检查数据重演捕获持续时间是否到期,若到期则自动停止捕获。
(4)执行动态缓冲区检查,根据需要动态扩展或动态收缩系统缓冲池。
(5)自动执行检查点。为了保证日志的及时刷盘,缩短系统发生故障时需要的恢复时间,根据INI参数设置的自动检查点执行间隔定期执行检查点操作。
(6)会话超时检测。若用户连接设置了连接超时,则定期检测连接是否超时,如果超时则自动断开连接。
(7)在必要时执行数据更新页刷盘。
(8)唤醒等待的工作线程。
5)日志刷新(FLUSH)线程
任何数据库的修改,都会产生重做(REDO)日志,为了保证数据故障恢复的一致性,REDO日志的刷盘必须在数据更新页刷盘之前进行。事务在运行时,会把生成的REDO日志保留在日志缓冲区中,当事务提交或执行检查点时,会通知日志 FLUSH 线程进行日志刷盘。由于日志具备顺序写入的特点,比数据页分散I/O写入效率更高,因此,日志FLUSH线程和I/O线程分开,能获得更快的响应速度,保证整体的性能。DM8的日志FLUSH线程进行了优化,在刷盘之前,对不同缓冲区内的日志进行合并,减少了I/O次数,进一步提高了系统性能。如果系统配置了实时归档,则在日志 FLUSH 线程刷盘前,会直接将日志通过网络发送到实时备机。如果系统配置了本地归档或远程同步归档,则生成归档任务,通过日志归档线程完成。
6)日志归档线程
日志归档线程包含同步归档线程和异步归档线程,前者负责本地归档和远程同步归档任务,后者负责远程异步归档任务。如果系统配置了非实时归档,则由日志 FLUSH线程产生的任务会分别加入日志归档线程,日志归档线程负责从任务队列中取出任务,按照归档类型进行相应归档处理。将日志FLUSH线程和日志归档线程分开的目的是减少不必要的效率损失,除远程实时归档外,本地归档、远程同步归档、远程异步归档都可以脱离日志FLUSH线程进行,如果放在日志FLUSH线程中一起进行,则会严重影响系统性能。
7)日志重做线程
为了提高故障恢复效率,达梦数据库在故障恢复时采用了并行机制重做日志,日志重做线程就用于日志的并行恢复。通过INI参数LOG_REDO_THREAD_NUM可配置日志重做线程数,默认是2个线程。
8)日志应用(APPLY)线程
在配置了数据守护的系统中,创建了一个日志 APPLY 线程。当服务器作为备机时,每次接收到主机的物理 REDO 日志都生成一个日志 APPLY 任务加入任务队列中,日志APPLY线程从任务队列中取出一个任务在备机上重做日志,并生成自己的日志,以保持和主机数据的同步或一致,作为主机的一个镜像。备机数据对用户只读,可承担报表、查询等任务,以均衡主机的负载。
9)定时器线程
在数据库的各种活动中,用户常常需要数据库在某个时间点开始进行某种操作,如备份,或者在某个时间段内反复进行某种操作等。定时器线程就是为这种需求设计的。在通常情况下,DM服务器需要进行定时操作的事件主要有以下几种。
(1)逻辑日志异步归档。
(2)异步归档日志发送(只在PRIMARY模式下,且在OPEN状态下发送)。
(3)作业调度。
定时器线程启动之后,每秒检测一次定时器链表,查看当前的定时器是否满足触发条件,如果满足,则把执行权交给设置好的任务,如逻辑日志异步归档等。在默认情况下,DM服务器启动的时候,定时器线程是不启动的。用户可以将dm.ini中的TIMER_INI参数设置为1来设置定时器线程在系统启动时启动。
10)逻辑日志归档线程
逻辑日志归档用于 DM8 的数据复制,目的是加快异地访问的响应速度。逻辑日志归档线程包含本地逻辑日志归档线程和远程逻辑日志归档线程。在系统配置了数据复制后,系统才会创建这两个线程。
(1)本地逻辑日志归档线程:本地逻辑日志归档线程从本地归档任务队列中取出一个归档任务,生成到逻辑日志,并将逻辑日志写入逻辑日志文件中。如果当前逻辑日志的远程归档类型是同步异地归档,并且当前的刷盘机制是强制刷盘,那么就生成一个异地归档任务加入临时任务队列中。
(2)远程逻辑日志归档线程:远程逻辑日志归档线程从远程归档任务队列中取出一个归档任务,并根据任务的类型进行相应的处理。任务的类型包括同步发送任务和异步发送任务。
11)数据守护相关线程
在配置了数据守护的观察器上,会创建观察器的实时检测线程、同步检测线程,实现主机和备机之间的故障检测、故障切换及故障恢复。在配置了数据守护进程的数据守护方案中,数据库实例还会创建 UDP 消息的广播和接收线程,负责数据库实例和守护进程之间的通信,实现数据守护功能。
12)MAL系统相关线程
MAL(Mail)系统是达梦数据库内部的高速通信系统,基于 TCP/IP 协议实现。DM服务器的很多重要功能都是通过 MAL 系统实现通信的,如数据守护、数据复制、大规模并行处理(MPP)、远程日志归档等。MAL系统内部包含一系列线程,有MAL监听线程、MAL发送工作线程、MAL接收工作线程等。
13)其他线程
达梦数据库系统中不止包括以上线程,在一些特定的功能中会有不同的线程,如回滚段清理线程、审计写文件线程、重演捕获写文件线程等,这里不再一一列出。
2.内存结构
数据库管理系统是一种对内存申请和释放操作频率很高的软件,如果每次对内存的使用都通过操作系统函数来申请和释放,则系统效率会比较低,因此加入自己的内存管理系统是达梦数据库系统管理必需的。通常,内存管理系统会带来以下好处:
(1)申请、释放内存效率更高;
(2)能够有效地了解内存的使用情况;
(3)易于发现内存泄露和内存写越界的问题。
达梦数据库管理系统的内存结构主要包括内存池、缓冲区、排序缓冲区、哈希缓冲区等。根据系统中子模块的不同功能,达梦数据库管理系统对内存进行了上述划分,并采用了不同的管理模式。
1)内存池
DM服务器的内存池指的是共享内存池,根据内存使用情况的不同,共享内存池的使用有两种工作方式:HEAP和VPOOL。共享内存池用于解决DM服务器对于小片内存的申请与释放问题。系统在运行过程中,经常会申请与释放小片内存,而向操作系统申请和释放内存时需要发出系统调用,此时可能会引起线程切换,降低系统运行效率。采用共享内存池可一次向操作系统申请一片较大内存,即内存池。当系统在运行过程中需要申请内存时,在共享内存池内进行申请;当用完该内存后,再释放,即归还给共享内存池。当系统采用较好的策略管理共享内存池时,小片内存的申请与释放不会对系统造成太大影响。这种方式还有一个优点,可以比较容易地检测系统是否存在内存泄露。达梦数据库系统管理员可以通过 DM 服务器的配置文件(dm.ini)来对共享内存池的大小进行设置,共享内存池的参数为MEMORY_POOL,该配置默认为40MB。而HEAP和VPOOL使用的是共享内存池中的内存,所以在一般情况下,HEAP和VPOOL两种工作方式申请的内存大小不会超过MEMORY_POOL的值。
(1)HEAP:HEAP 的工作方式采用了堆的思想,即每次在申请内存时,都是从堆顶上申请的,如果内存不够,则继续向共享内存池申请内存页,然后加入HEAP中,继续供系统申请使用,这样HEAP的长度可以无限增长下去;在释放HEAP时,可以释放堆顶上的内存页,也可以释放整个HEAP。使用内存堆来管理小片内存的申请有一个特点,每次在申请小片内存后,不能单独对这片内存进行释放,也就是不用关心这片内存何时释放,而是在堆释放时统一释放,这样就能有效防止内存泄露的发生。
(2)VPOOL:VPOOL工作方式主要采用了“伙伴系统”的思想进行管理。申请的VPOOL内存分为私有VPOOL和公有VPOOL两种。私有VPOOL只提供给某个单独功能模块使用,公有VPOOL则提供给那些需要共享同一资源而申请的模块,所以需要对公有VPOOL进行保护,而私有VPOOL则不需要保护。
VPOOL和HEAP的区别在于,VPOOL申请的每片内存都可以单独进行释放。
2)缓冲区
(1)数据缓冲区。
数据缓冲区是DM服务器在将数据页写入磁盘之前,以及从磁盘上读取数据页之后,数据页存储的地方。数据缓冲区是DM服务器至关重要的内存区域之一,将其设定得太小,会导致缓冲页命中率低,磁盘 I/O 操作频繁;将其设定得太大,又会导致操作系统内存本身不够用。系统在启动时,首先根据配置的数据缓冲区大小向操作系统申请一片连续内存,并将其按数据页大小进行格式化,置入自由链中。数据缓冲区存在 3 条链来管理被缓冲的数据页:一条是自由链,用于存放目前尚未使用的内存数据页;一条是LRU链,用于存放已被使用的内存数据页(包括未修改的和已修改的);还有一条是脏链,用于存放已被修改的内存数据页。LRU链对系统当前使用的数据页按最近是否被使用的顺序进行排序。这样,当数据缓冲区中的自由链被用完时,从LRU链中淘汰部分最近未使用的数据页,能够最大限度地保证被淘汰的数据页最近不会被用到,以减少I/O操作。在系统运行过程中,通常存在一部分“非常热”(反复被访问)的数据页,将它们一直留在缓冲区中,对系统性能会有好处。数据缓冲区开辟了一个特定的区域用于存放这部分数据页,以保证这部分数据页不参与一般的淘汰机制,可以一直留在数据缓冲区中。
① 类别:DM服务器中有4种类型的数据缓冲区,分别是NORMAL缓冲区、KEEP缓冲区、FAST缓冲区和RECYCLE缓冲区。其中,用户在创建表空间或修改表空间时,可以指定表空间属于NORMAL缓冲区,还是属于KEEP缓冲区。RECYCLE缓冲区供TEMP表空间使用,FAST 缓冲区根据用户指定的 FAST_POOL_PAGES 和 FAST_ROLL_PAGES大小由系统自动进行管理,用户不能指定使用RECYCLE缓冲区和FAST缓冲区中的表或表空间。NORMAL 缓冲区主要提供给系统处理的一些数据页,在没有特定的指定缓冲区的情况下,默认缓冲区为 NORMAL 缓冲区;KEEP 缓冲区的特性是很少或几乎不怎么对缓冲区中的数据页进行淘汰,主要针对用户的应用是否需要经常处在内存当中,如果是,则可以指定缓冲区为KEEP缓冲区。DM服务器提供了可以更改这些缓冲区大小的参数,用户可以根据自己的应用需求情况,指定dm.ini文件中BUFFER(80MB)、KEEP(8MB)、RECYCLE(64MB)、FAST_POOL_PAGES(0)和 FAST_ROLL_PAGES(0)的值(括号中为默认值),这些值分别对应NORMAL缓冲区的大小、KEEP缓冲区的大小、RECYCLE缓冲区的大小、FAST缓冲区的页面数和FAST缓冲区的回滚页面数。
② 读多页:在需要进行大量I/O操作的应用中,达梦数据库之前版本的策略是每次只读取 1 个数据页。如果知道用户需要读取表的大量数据,当读取到第一页时,可以猜测用户可能需要读取这一页的下一页,在这种情况下,一次性读取多个数据页就可以减少I/O操作次数,从而提高数据的查询、修改效率。DM服务器提供了可以读取多个数据页的参数,用户可以指定这些参数来调整数据库运行效率的最佳状态。在DM服务器的配置文件dm.ini中,可以指定参数MULTI_PAGE_GET_NUM的大小(默认值为16页),以控制每次读取的数据页数。如果用户没有设置较适合的参数MULTI_PAGE_GET_NUM的大小,有时可能会给用户带来更差的运行效果。如果 MULTI_PAGE_GET_NUM 的值太大,每次读取的数据页可能大多不是以后所用到的数据页,这样不仅会增加 I/O 的操作次数,而且每次都会做一些无用的 I/O 操作,所以系统管理员需要衡量好自己的应用需求,给出最佳方案。
(2)日志缓冲区。
日志缓冲区是用于存放重做日志的内存缓冲区。为了避免由于直接的磁盘I/O操作而使系统性能受到影响,系统在运行过程中产生的日志并不会立即被写入磁盘,而是和数据页一样,先被存放到日志缓冲区中。那么,为何不在数据缓冲区中存放重做日志,而要单独设立日志缓冲区呢?其主要原因如下。
① 重做日志的格式同数据页完全不一样,无法进行统一管理。
② 重做日志具备连续写的特点。
③ 在逻辑上,写重做日志比数据页I/O操作优先级更高。
DM服务器提供了参数LOG_BUF_SIZE,以对日志缓冲区大小进行控制,日志缓冲区所占用的内存是从共享内存池中申请的,单位为页,并且大小必须为2 N 页,否则采用系统默认大小256页。
(3)字典缓冲区。
字典缓冲区主要存储一些数据字典信息,如模式信息、表信息、列信息、触发器信息等。每次对数据库的操作都会涉及数据字典信息,访问数据字典信息的效率直接影响到相应的操作效率。例如,进行查询操作,就需要相应的表信息、列信息等,这些数据字典信息如果都在缓冲区中,则直接从缓冲区中获取即可,否则,需要I/O操作才能读取这些信息。DM8采用将部分数据字典信息加载到缓冲区中,并基于LRU算法进行数据字典信息的控制。缓冲区如果设置得太大,会浪费宝贵的内存空间;如果设置得太小,可能会频繁地进行数据页淘汰,该缓冲区配置的参数为DICT_BUF_SIZE,默认的配置大小为5MB。DM8采用缓冲部分数据字典对象的方式,这会影响系统效率吗?数据字典信息访问存在热点现象,并不是所有的数据字典信息都会被频繁访问,所以按需加载数据字典信息并不会影响系统实际的运行效率。但是,如果在实际应用中涉及对分区数量较多的水平分区表的访问,如上千个分区,就需要适当调大DICT_BUF_SIZE参数的值。
(4)SQL缓冲区。
SQL缓冲区提供在执行SQL语句过程中所需要的内存,包括执行计划、SQL语句和结果集存放。在很多应用中都存在反复执行相同SQL 语句的情况,此时可以使用缓冲区保存这些SQL语句和它们的执行计划,这就是计划重用。这样做带来的好处是加快了SQL语句的执行效率,但同时给内存增加了压力。DM服务器的配置文件dm.ini中提供了参数来支持是否需要计划重用,参数为USE_PLN_POOL,当该参数指定为1时,启动计划重用;否则,禁止计划重用。达梦数据库还提供了参数 CACHE_POOL_SIZE(单位为 MB)来改变SQL缓冲区的大小,系统管理员可以设置该参数值以满足应用需求,默认值为10MB。
3)排序缓冲区
排序缓冲区提供数据排序所需要的内存空间。用户在执行SQL语句时,通常需要进行排序,所使用的内存就是排序缓冲区提供的。在每次排序过程中,系统都先申请内存,在排序结束后再释放内存。DM 服务器提供了参数来指定排序缓冲区的大小,参数SORT_BUF_SIZE在DM服务器的配置文件dm.ini中,系统管理员可以设置其大小以满足需求。由于该参数值是由系统内部的排序算法和排序数据结构决定的,因此建议使用默认值2MB。
4)哈希缓冲区
DM8提供了为哈希连接而设定的缓冲区,不过该缓冲区是虚拟缓冲区。之所以说是虚拟缓冲区,是因为系统没有真正创建特定的属于哈希缓冲区的内存,而是在进行哈希连接时,对排序的数据量进行了计算。如果计算得出的数据量超过了哈希缓冲区的大小,则使用 DM8 创新外存哈希方式;如果计算得出的数据量没有超过哈希缓冲区的大小,实际上使用的还是VPOOL内存池进行的哈希操作。DM服务器在配置文件dm.ini中提供了参数HJ_BUF_SIZE来进行控制,由于该参数值的大小可能会限制哈希连接的效率,所以建议保持默认值,或者设置为更大的值。
除提供 HJ_BUF_SIZE 参数外,DM 服务器还提供了创建哈希表个数的初始化参数,其中,HAGR_HASH_SIZE 表示在处理聚集函数时创建哈希表的个数,建议保持默认值100000个。
5)SSD缓冲区
固态硬盘(SSD)采用闪存作为存储介质,因没有机械磁头的寻道时间,其读写效率比机械磁盘更有优势。内存、SSD、机械磁盘均符合存储分级的条件。为提高系统执行效率,DM服务器将SSD文件作为内存缓存与普通磁盘缓存之间的缓冲层,称为SSD缓冲。DM服务器在dm.ini中提供参数SSD_BUF_SIZE和SSD_FILE_PATH来配置SSD缓冲区,SSD_BUF_SIZE用于指定SSD缓冲区的大小,单位是MB,DM服务器根据该参数创建相应大小的文件作为缓冲区使用;SSD_FILE_PATH指定SSD文件所在的文件夹路径,管理员需要保证设置的路径位于固态磁盘上。
默认SSD缓冲区是关闭的,即SSD_BUF_SIZE为0。若要配置SSD缓冲区,则将其设置为大于 0 的数,并指定 SSD_FILE_PATH 即可。根据存储分级的概念,建议将SSD_BUF_SIZE的值配置为BUFFER_SIZE值的2倍左右。