内容


第 1 部分

调优 Informix SQL

示例和分析

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: 第 1 部分

敬请期待该系列的后续内容。

此内容是该系列的一部分:第 1 部分

敬请期待该系列的后续内容。

简介

通常认为 SQL 查询的调优是程序员和开发人员的主要责任,但是数据库管理员也应积极参与该过程。数据库管理员参与 SQL 查询调优的主要好处之一是,他们可以提出不同的观点。程序员是从应用程序性能的角度来考虑问题的,而 DBA 考虑问题时理解了数据库本身,从而可以对数据库的布局、表和索引的安排,以及 Informix 和系统资源(包括数据分段、PDQ 优先级、CPU 时间、内存利用率和数据存储)的有效使用提出意见和建议。有时,程序员和开发人员就性能而言仅仅需要获取不同的查询视图,因此他们可以修改该查询,以获得更高的效率。

本文将介绍多种调优方法。 第 1 部分将介绍调优标准、工具以及一套通用方法。此外,还将讨论优化器的角色,其中包括 OPTCOMPIND 参数、查询命令和内部统计数据。

第 2 部分仍然是调优,我将介绍查询本身的性能考虑,其中包括访问方法、连接方法、表和索引的区段、索引层次、分段以及 PDQ 优先级。第 2 部分还将包含示例及分析。

调优标准

调优标准基本上是依据个人的业务需求而定的。一般,主要涉及系统和数据库的性能。那么您又该如何配置系统和数据库性能呢?有多方面的考虑,但是最关键的就是 响应时间资源利用率。响应时间指的是用户等待他们的请求(即 SQL 查询)得到完成的时间。资源利用率指的是执行 SQL 查询时,CPU、内存和磁盘等系统资源的使用。

通常,如果完成调优过程之后,调优之后的 SQL 查询的响应时间变短了,而系统资源的利用率降低了,那么您就可以充满信心地推断:您已经调优该 SQL 查询,并获得了更高的效率。如何测量 SQL 查询的响应时间和资源利用率呢?Unix 和 Informix 提供了一些工具和实用程序,帮助我们科学、定量地测量响应时间和资源利用率。

调优工具

Unix 工具

Time 和 timex

您可以使用 time 实用程序来报告一些系统操作的响应时间,例如文件传送、数据库的查询执行以及其他活动。下面的实例展示了如何使用 time 实用程序来测量一个简单数据库查询的响应时间:

sys3523:omcadmin > time dbaccess airgen_cm_db sel.sql
Database selected.
      		(count(*)) 
           	 5958
1 row(s) retrieved.
Database closed.
real    0m0.09s
user    0m0.01s
sys     0m0.06s

上面输出的最后一部分给出了详细的操作时间统计数据,该操作在本例中就是数据库查询:

  • “real”字段告诉您从查询开始到结束时所经过的时间。
  • “user”字段告诉您用户处理器为该操作而占用的 CPU 时间总和。
  • “sys”字段告诉您整个系统占用的 CPU 时间总和。

我们最感兴趣的是“real”字段;该字段表示操作的响应时间。让我们仔细查看一下上面的这个例子。通过输出,我们可以确定该查询的响应时间是 0.09 秒。

Timex 只是 time 实用程序的另一个变种,它将以更易读的格式显示时间。下面是同一查询的 timex 输出:

sys3523:omcadmin > timex dbaccess airgen_cm_db sel.sql
Database selected.
      (count(*)) 
            5958
1 row(s) retrieved.
Database closed.
real        0.09
user        0.02
sys         0.04

Vmstat

vmstat 实用程序深入挖掘系统并报告系统资源使用的统计数据,主要涉及运行的处理器、虚拟内存、磁盘 I/O、中断和 CPU。它还显示一行系统重启或启动以后的虚拟内存活动的摘要信息。下面是一个输出示例:

sys3523:omcadmin > vmstat 1 10
 procs     memory            page            disk          faults      cpu
 r b w   swap  free  re  mf pi po fr de sr m0 m1 m4 m5   in   sy   cs us sy id
 0 0 0 1959208 1294824 141 824 1 1 1  0  0  0  0  0  0  906  946  700  2  3 95
 0 0 0 1995568 1260288 0 46  0  0  0  0  0  0  0  0  0  834  386  213  0  0 100
 0 0 0 1995568 1260288 0 40  0  0  0  0  0  0  0  0  0  884  265  199  0  1 99
 0 0 0 1995568 1260288 0 40  0  0  0  0  0  0  0  0  0  834  325  186  0  0 100
 0 0 0 1995568 1260288 43 286 0 0  0  0  0  0  0  0  0  869 1682  242  0  1 99
 0 0 0 1995352 1260048 658 3503 0 0 0 0  0  0  0  0  0  827 21930 375  3 14 83
 0 0 0 1995408 1260240 662 3495 0 0 0 0  0  0  0  0  0  825 22010 387  4 13 83
 0 0 0 1995568 1260288 121 691 0 0 0  0  0  0  0  0  0  834 4310  261  1  3 96
 0 0 0 1995568 1260288 0 40  0  0  0  0  0  0  0  0  0  824  250  188  0  0 100
 0 0 0 1995568 1260288 0 40  0  0  0  0  0  0  0  0  0  824  365  214  0  0 100

vmstat 实用程序接收两个整数参数:time interval 和 count。Time interval 指定 vmstat 刷新的间隔,而 count 指定它将刷新的最大次数。如果未指定任何参数,vmstat 就只会列出系统的前一次统计数据,而且不会进行刷新。本例中,它所提供的统计数据是不准确的,也不是最新的。如果指定了 interval,vmstat 将立即反复按照最新的间隔总结系统活动的概要信息。如果给定了 count,vmstat 就会重复获取系统的统计数据,直到达到了所指定的 count 次数。

输出中最让我们感兴趣的是“r”、“po”和“id”字段。

  • “r”字段告诉我们系统就绪队列中有多少任务在等待要执行的资源。
  • “po”字段告诉我们当前内存中有多少页面被换出。如果该数字极其庞大,并持续增长,这通常表示物理存储器或 RAM 不足,您可能需要安装更多存储器。
  • “id”字段告诉我们当前使用了多少系统 CPU 资源。

这些字段一起将让您较好地了解当前系统资源的使用情况。

Informix 工具

Informix 提供的用来收集详细 SQL 查询计划和执行统计数据的最全面的工具是 SET EXPLAIN 实用程序。该实用程序将生成一个名为 sqexplain.out 的文件,并详细记录查询的每个执行步骤。此外,它还提供估算的查询成本,并预计查询结果。通过检查 SET EXPLAIN 输出文件,您可以确定是否可以采取措施来提高该查询的性能。以下示例展示了一个极其复杂查询的 set explain 输出:

QUERY:
------
SELECT --+AVOID_FULL(omchn)+AVOID_FULL(daphn)
                omchn.omc_hn_uanc,
                nvl(daphn.gtt_version,"0000000000000000000"),
                nvl(idachn.egt4_version,"0000000000000000000"),
                nvl(ihlrhn.hlr_timestamp,"00000000000000"),
                vsgw_hn.hn_igw_uanc,
                nvl(vsgw_hn.hn_igw_version, "00000000000000")
           FROM omchn, daphn, idachn, ihlrhn, vsgw_hn
          WHERE daphn.dap_hn_inst  = omchn.omc_hn_inst
            AND idachn.idac_hn_inst = omchn.omc_hn_inst
            AND ihlrhn.hlr_hn_inst = omchn.omc_hn_inst
            AND vsgw_hn.vsgw_hn_inst = omchn.omc_hn_inst
DIRECTIVES FOLLOWED:
AVOID_FULL ( omchn )
AVOID_FULL ( daphn )
DIRECTIVES NOT FOLLOWED:
Estimated Cost: 8
Estimated # of Rows Returned: 1
  1) root.idachn: SEQUENTIAL SCAN
  2) root.daphn: INDEX PATH
    (1) Index Keys: dap_hn_inst   (Serial, fragments: ALL)
        Lower Index Filter: root.daphn.dap_hn_inst = root.idachn.idac_hn_inst
NESTED LOOP JOIN
  3) root.vsgw_hn: SEQUENTIAL SCAN
NESTED LOOP JOIN
  4) root.omchn: INDEX PATH
        		Filters: root.vsgw_hn.vsgw_hn_inst = root.omchn.omc_hn_inst
    		(1) Index Keys: omc_hn_inst   (Serial, fragments: ALL)
      Lower Index Filter: root.idachn.idac_hn_inst = oot.omchn.omc_hn_inst
NESTED LOOP JOIN
 	 5) root.ihlrhn: INDEX PATH
    		(1) Index Keys: hlr_hn_inst   (Serial, fragments: ALL)
      Lower Index Filter: root.ihlrhn.hlr_hn_inst = root.omchn.omc_hn_inst
NESTED LOOP JOIN

可将以上输出分成三个部分:

  • 第一部分展示了查询语法。
  • 第二部分展示了该查询的估算成本。
  • 第三部分详细地解释了所执行查询的每一步。

我们最感兴趣的是第二和第三部分。估算成本是优化器用来比较查询计划的成本单元。这些单元不直接转换成时间;它们表示的是典型磁盘访问的相对时间。

优化器将选择该查询计划,因为其执行的估算成本是所有被估计划中最低的。与具有较低估算成本的运行相比,具有较高估算成本的查询的运行时间通常更长一些。第三部分对于查询调优是至关重要的,因为它提供了大量有用的信息,例如查询所用的数据访问方法和连接方法。以上示例展示了如何使用连续扫描和索引来进行数据检索,以及如何使用嵌套循环连接方法来连接所有表。稍后我将在本文中详细讨论这一点。

该实用程序易于使用。如果需要知道某个 SQL 查询的详细查询执行计划,只需在最初的查询之前添加如下所示 SET EXPLAIN ON 语句即可:

set explain on;
select count(*) from acg;

然后,Informix 服务器将在用户 home 目录中生成一个名为 sqexplain.out 的文件,正如上面谈到的,其中将记录详细的查询执行计划及其成本。该文件是累积的,换言之,如果 SET EXPLAIN ON 语句之后有多个 SQL 查询,每个查询的执行计划及其成本都会被追加到文件中,直到将之删除。同样,对于存储过程,您需要对原始的存储过程执行 UPDATE STATISTICS,以获取详细的执行计划,因为在更新统计数据时,存储过程只可以更新它们的查询执行计划。例如,如果您需要查看存储过程 dap_int 的详细执行计划,就需要进行下列操作:

set explain on;
update statistics for stored procedure dap_int();

从版本 9.3 开始,该实用程序得到了较好的提高;您可以获取详细的查询执行计划,而不必执行该查询。这使您可以在真正的生产环境中获取查询执行计划。要使用这项新功能,需要在 SET EXPLAIN ON 语句中使用关键字 AVOID_EXECUTE,如下所示:

set explain on avoid_execute;
select count(*) from act;

关于如何使用该实用程序的详细信息,请参阅 IBM Informix Dynamic Server Administrator's Guide, Version 9.4

通用方法

那么我们如何在 SQL 查询的调优中应用那些工具呢?不同的人可能有不同的方法,但是,一般应按照下列方法和步骤进行:

  1. 收集关于原始 SQL 查询的统计数据。在这一步中,需要使用上面讨论的工具来获取该查询的统计数据:其响应时间、详细的执行计划和成本,以便稍后进行深入分析。
  2. 分析统计数据。在这一步中,需要挖掘上面所收集的统计数据,并仔细查看查询执行计划。如上所述,性能是查询调优中主要关心的问题。在检查查询计划时,需要考虑影响性能的所有因素:访问方法、连接方法、子查询、表和索引区段、表和索引分段等。稍后我将在本文的第 2 部分中逐个详细地讨论这些因素。
  3. 设置测试环境。这是一个极其重要的步骤。就硬件和软件配置而言,应将测试环境设置为与运行查询的生产系统完全相同或极其相似。例如,如果生产机器有 6 个 400HM 的 CPU,那么测试机器也应该有 6 个 400HM 的 CPU;否则,随后的测试将是无效且不可靠的。请记住,所有那些查询最终都将在生产中运行。
  4. 修改并测试新的查询。这是调优中的一个主要步骤,同时也是最冗长乏味的一个步骤。一次修改原始查询的一个地方,并进行测试,以查看是否提高了性能(减少了响应时间)。记录测试细节,例如您所做的修改、响应时间和执行计划。进行了修改之后,如果查询性能没有优于您原始查询的,就撤销修改。测试必须是有效且可靠的;换言之,测试必须是可重复的。例如,如果对同一查询进行两次相同的测试,第一次输出了一个极佳的响应时间(比如说 10 秒),但是第二次,响应时间就增加到 30 秒,那么您的测试就是不可重复的,因为响应时间的差异过大。您需要重新检查测试过程,并识别那两次测试之间的差异。如果测试是可重复的,那么测试结果之间的差异应该是极小的。
  5. 分析测试结果。在分析测试结果时,我们需要检查测试结果的有效性和可靠性。我们需要检查硬件、软件、工作负载以及其他所有因素,以确保测试结果是有效且可靠的。
  6. 在生产系统中实现改进。在实现之前,您需要进行最新的详细检查,并确保新的查询在生产中不会导致任何问题。

优化器及其角色

与 Oracle 和 SQL Server 等其他关系数据库管理系统一样,Informix 也有内部优化器,负责选择最佳的查询执行计划。分析了 SQL 查询之后,优化器将通过分析磁盘 I/O 和 CPU 成本等因素,考虑所有执行查询的可能方法。然后,它会用由下至上、宽度优先(bottom up, breadth-first)的搜索策略,同时构造所有可行的计划。

换言之,优化器首先将构造所有可能的连接计划,然后删除所有花费较高的冗余对(redundant pair),这些冗余对是包含相同表以及产生与另一连接对相同的行集的连接对。如果某查询使用了附加的表,那么优化器就将每个剩余对连接一个新表,以形成所有可能的连接三元组,排除代价更为昂贵的冗余三元组,如此一来就连接了每个附加的表。当生成了非冗余的可能连接组合集时,优化器就选择看上去具有最低执行成本的计划。例如,优化器必须确定是否应使用索引。如果该查询包含了连接,那么优化器就必须确定连接计划(hash、sort merge 或 nested loop),以及评估或连接表的次序。

优化器将根据在每个表中检索的行数来评估查询成本。被评估的行数则基于 WHERE 子句里所使用的每个条件表达式的选择性。优化器使用 UPDATE STATISTICS 所生成的数据分布信息来计算查询中筛选器的选择性。然而在缺乏数据分布信息的情况下,优化器将基于表索引计算不同类型筛选器的选择性。例如,如果索引列包含字面值和 NULL 值,那么其选择性就等于索引中不同的键的数目。关于在缺乏数据分布的情况下,优化器用以计算选择性的详细表,请参阅 Performance Guide 的第 10 章。但是,使用该方式计算的选择性不如使用数据分布计算的选择性准确。

因此,选择性估算的准确性显然基于您运行 UPDATE STATISTICS 的频率。如果频繁地运行 UPDATE STATISTICS,优化器就会更准确地计算出选择性,因为每次运行 UPDATE STATISTICS 时,都会更新数据分布,除了运行带有 low 选项的 UPDATE STATISTIC 之外。

当优化器创建查询计划时,它将使用下列系统目录信息:

  • 从最新的 UPDATE STATISTICS 语句起,表中的行数。
  • 将哪一列限定为惟一的。
  • 当请求 UPDATE STATISTICS 语句中带有 MEDIUM 或 HIGH 关键字时,列值的分布情况。
  • 包含行数据的磁盘页的数目。
  • 存在于表上的索引,包括它们索引的列,哪些是升序或降序的,以及哪些是群集的。
  • 索引结构的深度(衡量执行索引查找所需的工作量)。
  • 索引项占用的磁盘页数目。
  • 索引中的惟一项数目,可用于估算等式筛选器所返回的行数。
  • 索引列中第二大和第二小的键值。

优化器的行为受三个关键因素的影响:Informix 配置文件中 OPTCOMPIND 参数的值、查询命令和内部统计数据的准确性。

OPTCOMPIND 参数

OPTCOMPIND 是一个环境变量,或者是 Informix 配置文件中的一个参数。优化器用其值来选择数据访问方法。其值是 0、1 和 2 这三个中的一个,分别表示下列意思:

  • 如果将其值设置为 0,那么当存在合适的索引时,优化器就选择索引扫描而非表扫描,甚至不考虑估算成本。
  • 如果将其值设置为 1,那么当事务隔离模式不是可重复读(Repeatable Read)时,优化器的行为就与值为 0 时一样。如果事务隔离模式是可重复读(Repeatable Read),那么优化器会将其选择完全基于估算成本。
  • 如果将其值设置为 2,优化器就会使用估算成本来确定执行计划,而不管事务隔离模式如何。

您可以将 OPTCOMPIND 设置为环境变量,也可以设置为配置文件中的参数,但是,将之设置为参数将优先执行。

查询命令

影响优化器的另一种方式就是使用查询命令。查询命令是 SQL 查询中的提示,指示优化器如何执行查询。一共有 4 种类型的查询命令,如下所示:

  • 访问计划指示,强制优化器使用指定的访问方法进行数据检索,要么是连续扫描,要么是索引扫描。
  • 连接次序指示,强制优化器按照指定次序连接表。
  • 连接计划指示,强制优化器使用指定的连接方法来连接查询中的表,要么是嵌套循环连接、分类合并连接,要么是动态哈希连接。
  • 目标指示,强制优化器使用指定的规则来返回查询结果。

关于如何使用那些指示的详细信息,请参阅 IBM Informix Dynamic Server Performance's Guide, Version 9.4 的第 11 章。

内部统计数据

通过内部统计数据,我指的是系统目录中的统计数据,优化器可以确定最低成本的查询执行计划。为了确保优化器选择最佳的查询计划,使内部统计数据保持为最新并且最准确的十分重要。数据库服务器将初始化表、索引、存储过程和触发器等数据库对象的统计配置文件,并在创建数据库表时,将数据分布置于系统目录中,但不自动更新那些统计数据。

要使统计配置文件保持最新,您需要定期运行 UPDATE STATISTICS;否则,您系统的统计配置文件可能无法反映您系统的当前状态,而优化器则可能无法在众多查询执行计划中做出正确选择。UPADTE STATISTICS 有三种运行模式,一般每次执行修改了大量表数据的大量批作业之后,以及每次向表添加索引之后,您都需要运行 UPDATE STATISTICS。关于如何执行 UPDATE STATISTICS 的详细信息,请参阅 IBM Informix Dynamic Server Administrator's Guide, Version 9.4。其经验法则就是:越频繁地运行 UPDATE STATISTICS,系统的统计配置文件将越新、越准确,而优化器则越可能选择最佳的查询执行计划。

虽然如上面所谈论的,优化器的行为受 OPTCOMPIND 和查询命令的影响,但优化器通常是基于下列指导方针来选择查询计划:

  • 如果查询从一个表检索大量数据,优化器就不会使用索引。例如,如果您公司的客户非常均匀地分布在所有 50 个州中,而您需要检索除了纽约之外的每个州的客户信息,那么您需要执行下列查询:
    SELECT * FROM customer WHERE STATE <> "NEW YORK";

    优化器将立刻检测您可能要检索的表中的 98% 的数据,它认为连续读或扫描表要比遍历索引(以及随后的数据页)更加高效,然后它将检索相关数据。
  • 如果表上定义了多个索引,那么优化器就使用可以排除表中最多数据的索引。例如,如果您公司拥有 200,000 位纽约的客户,而只有约 1000 位客户在同一天发出了订单,比如 1997 年 1 月 20 日,那么您可以使用下列查询来获取他们的姓名和地址:
    SELECT name, address FROM customer 
    WHERE state = "NEW YORK" AND order_date = "01/20/97"

    优化器极可能会选择使用 order_date 上的索引,而不是选择使用 state 上的索引。
  • 如果查询中没有指示,那么优化器通常会首先从带有最多限制性筛选器的表中检索数据。让我们查看下列查询:
    SELECT * FROM customer, orders
    WHERE customer.customer_num = orders.customer_num
    AND   customer.state = "NEVADA";

    本例中,优化器所做的第一件事就是评估 state 等于 NEVADA 的这个条件,因为这将排除表中的大量数据行。然后,它将连接两个表。其思想就是尽可能多地减少数据库服务器的工作负载。如果优化器首先连接两个表,那么连接结果可能十分庞大,并可能使用大量系统资源,如 CPU 和内存。如果您拥有 1,000,000 位活动客户,平均每人每月发出一份订单,那么连接结果将至少返回 1,000,000 条记录,这肯定会损害您的系统性能。
  • 如果连接列上不存在索引,那么优化器将选择动态哈希连接。在前一个实例中,如果 customer.customer_num 和 orders.customer_num 都没有被索引,那么优化器将选择动态哈希连接来作为最佳的执行计划。
  • 如果满足下列条件,优化器将选择嵌套循环连接:
    • 在数据库服务器使用所有表筛选器之后,从外部表检索出的行数将很少,而内部表具有一个可用于执行连接的索引。
    • 可以用最外面的表上的索引,以 ORDER BY 子句的次序返回行,从而消除排序的需要。

结束语

在本文的第 1 部分中,我讨论了调优规则,谈到了您将需要的工具,并介绍了用于调优过程的基本方法。在第 2 部分中,我将深入这个过程,查看查询本身,并查看一些示例。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Information Management
ArticleID=49930
ArticleTitle=第 1 部分: 调优 Informix SQL
publish-date=11012004