【IT168 技术】在上一篇文章《达梦7.0新版本即将发布 新特性抢先看》里,我们介绍了达梦即将推出新一代高性能数据库产品DM7.0的消息。同时,我们还为大家介绍了DM7.0的新特性之一水平分区。作为介绍DM7.0的系列文章,今天,我们为大家介绍DM7.0的另一个新特性:动态性能监视。
概述
早期的达梦数据库服务器基本上是一个黑盒子,用户用来观察系统内部运行状态的手段比较有限,不利于系统的性能调优和故障诊断,这个局面在新版本中得到了极大地改善。为了帮助程序员和数据库管理员了解达梦数据库内部的运行状态,达梦数据库7.0版本提供了大量的动态表,这些动态表记录了内部各个主要子系统的重要运行时信息。分析这些动态表提供的数据,可以很容易地定位性能瓶颈,并进行针对性的优化。
动态表的名字都以V$开头,它们可以象普通表一样参与任何合法的查询,但是动态表的维护与更新,都由系统自动完成,用户不能用SQL语句更新、插入或删除动态表中的数据。动态表的数据显然也不符合普通表的ACID特性,因为数据是系统自动生成,事实上,它们反应的是系统内部数据结构的状态。有经验的达梦数据库用户可以通过这个窗口了解达梦数据库系统的设计思想和运行逻辑,考察系统设计的优劣,对比同类产品的相关特性,并得出客观的结论。
动态表在系统第一次启动时由系统自动创建,可以查看SYSOBJECTS来获得全部动态表的清单:
SELECT DISTINCT NAME FROM SYSOBJECTS WHERE NAME LIKE ‘V$%’;
因为有些和表名同名的同义词,因此需要使用DISTINCT修饰来过滤重复的名字。
线程
达梦数据库是一个单进程多线程系统。和多进程系统相比,线程的切换代价更小,线程间的数据共享也更容易,实现起来也相对比较容易。V$THREADS记录了系统正在运行的线程,该表定义如下:
ID INTEGER,
NAME VARCHAR(32),
START_TIME DATETIME
);
表中每一行对应一个线程。所谓名字,其实是这个线程的工作函数在DM7.0源码中的名字。这些线程的功能大致按下表分类:
大部分线程的数量是不变的。 有几个例外,os_io_thread的数量可以在ini文件中配置,sess4_scan_thread也会随着连接数的增加或者减少而动态变化,通常每64个连接对应一个sess4_scan_thread。
对于工作线程(ntsk_worker_thread), 系统缺省的工作线程数量为4个。和早期的版本不同,系统会按照用户连接数和工作负载的变化,在预先设定的范围内,动态地创建或者销毁工作线程。这些动态的创建与销毁历史,记录在V$WTHRD_HISTORY中:
SEQNO INTEGER,
THREAD_ID BIGINT,
CHG_TYPE VARCHAR(24),
CHG_TIME DATETIME);
其中chg_type记录了变化的原因,有下面5个取值:
2 Exit_Too_Many 工作线程太多而退出
3 Reuse_OK 服务于本会话的线程,继续为本会话服务
4 Reuse_fail 服务线程,因为没有及时收到用户的响应而转入主任务队列
5 To_Idle 不重用,直接转入主任务队列
在达梦数据库系统中,用户连接与工作线程不是简单的一对一的关系,在任何一个时间点,只有一个工作线程(并行执行计划除外)为一个连接服务,但是同一个事务的不同的SQL语句,可以由不同的工作线程来完成。
等待事件
由于共享资源冲突等原因,线程在处理SQL命令的过程中,可能会不得不等待一个事件的结束。跟踪并分析等待历史,有助于管理员了解系统内部的资源争用情况。系统记录了几大典型的等待事件的历史:
2 ROW LOCK WAITING, 行锁等待
3 TABLE LOCK WAITING,表锁等待
4 DICT LOCK WAITING, 字典锁等待
5 TASK WAITING, 工作线程空闲等待
6 NETWORK WAITING, 网络IO等待
7 REDO LOG FLUSH WAITING,事务提交时,redo日志刷盘等待
8 PAGE CONFLICT, 数据页争用等待
9 BUFFER WAITING, 系统缓冲区争用等待
V$WAIT_HISTORY记录了这些等待事件的历史, 定义如下:
THREAD_ID BIGINT, /* 线程ID */
TRX_ID BIGINT, /* 事务 ID */
WAIT_CLASS SMALLINT, /* 等待的类别 */
WAIT_OBJECT BIGINT, /* 等待对象 */
WAIT_START DATETIME, /* 开始等待的时间 */
WAIT_TIME BIGINT, /* 以微秒为单位 */
SPACE_ID SMALLINT, /* 如果是页冲突,页所在的表空间ID */
FILE_ID SMALLINT, /* 如果是页冲突,页所在的文件ID */
PAGE_NO INTEGER, /* 如果是页冲突,页的页号 */
LOCK_ID INTEGER); /* 锁的ID */
系统在内部开辟了一个数组,每发生一次等待,就在该数组中注册一个项;结束等待时,就修改这个项的等待时间信息。这个数组循环使用,老的等待项会被淘汰掉。
SQL执行监视
DBA和程序员都很关心SQL语句的执行效率,希望能找到系统执行慢的SQL语句,并进行必要的优化。动态表V$SQL_HISTORY记录了最近大约2000个SQL语句的执行情况:
系统为虚拟机的每次执行都赋予一个唯一的ID值(EXEC_ID), 并在这个表中注册一条记录,描述相应SQL语句执行的开始时间和总共所消耗的时间TIME_USED等信息。对于IS_OVER为FALSE的记录,表明该语句正在执行,还没有结束,TIME_USED字段通常情况下应该为0。但是对于长时间的语句,系统大概每隔5到20秒,修改这个TIME_USED的值。
通过查询这个V$SQL_HISTORY就可以找出性能低下的SQL语句。如果还想了解这个SQL语句对应的查询计划中每一个操作符的执行次数、执行时间等详细信息,则可以查询另一个动态表V$SQL_NODE_HISTORY:
使用类似下面的查询语句,可以了解执行ID为100的那个SQL语句的每个操作符号的执行情况(以执行时间进行倒序排列):
FROM V$SQL_NODE_HISTORY A, V$SQL_NODE_NAME B
WHERE A.EXEC_ID = 100 AND A.TYPE$ = B.TYPE$
ORDER BY 3 DESC;
这里的V$SQL_NODE_NAME记录了系统支持的每一个操作符的编号、名字和相关的功能描述。通过上面的查询,DBA可以很清楚地知道时间消耗在哪一个具体的操作符上。
小结
动态表是达梦数据库7.0的新特性,动态表基本覆盖了系统缓冲区、SQL的执行、日志、事务、回滚段等各子系统,全面地展示了系统内部的运行状态,为系统管理员、程序员、和系统调优势工程师提供了很有意义的参考价值。达梦数据库希望借助这些动态表,能为用户提供更多的性能调优手段和更好的易用性。