`

通过 UPDATE STATISTICS 充分利用 Informix Dynamic Server

阅读更多
通过 IBM® Informix® Dynamic Server(IDS)中的 UPDATE STATISTICS 语句充分利用数据库优化器。阅读本文对这个 SQL 语句的简述,了解如何用它解决各种不同的问题。发现更新统计信息的重要性,并了解如何收集统计信息。最后,浏览本文最后的 FAQ 小节,寻找您对这个重要的 SQL 语句所存疑问的答案。
<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->

简介http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0803changappa/

         UPDATE STATISTICS 是一个专用 Informix SQL 命令,它通过分析数据并将该信息存储在系统编目中,更新关于每个表以及它的列的实际信息,这些信息可用于估计随后查询的成本。要真正理解 UPDATE STATISTICS 的重要性,您需要理解当用户输入一个要执行的 SQL 查询时,到底会发生什么事情。输入的每个 SQL 查询都必须被解析、优化和执行。

优化器是用于准备查询计划的组件。理想情况下,查询计划是执行给定查询的最佳计划 — 也就是说,它会确定抓取数据的最佳方式。为此,它使用一个统计数据集合;然而,这种统计数据并不一定是准确的。这种数据的准确性取决于很多因素,例如采用的抽样算法的类型、抽样的数量和数据的歪斜情况。

查询优化器不会自动重新计算表的配置文件。在某些情况下,收集统计信息需要的时间可能比执行查询的时间更长。为确保优化器选择的查询计划能够最好地反映表的当前状态,应定期运行 UPDATE STATISTICS。

 

         初次装载数据和创建索引之后,应该运行 UPDATE STATISTICS。此外,每当对数据库表作出重大更改,包括大规模的插入、更新或删除时,也应该运行该命令。如果没有运行 UPDATE STATISTICS,则优化器只能使用不准确的数据来确定访问路径。

          现在,学习该命令的工作原理。 查询优化器根据从每个表检索的行数估计查询成本。而估算的行数取决于 WHERE 子句中使用的每个条件表达式的选择率。过滤器 是一个条件表达式,用于选择行。选择率是介于 0 到 1 之间的一个值,表示表中能通过过滤器的行所占的百分比。对于只通过很少行的选择率过滤器,它的选择率趋向于 0,对于能通过几乎所有 行的过滤器,它的选择率趋向于 1。

        优化器可以使用数据分布来计算查询中过滤器的选择率。但是,如果没有数据分布,则数据库服务器根据表索引计算不同类型的过滤器的选择率。

       选择率估值的准确性对每个执行计划的成本有很大影响。因此,获得最佳计划的准确性完全取决于关于查询中所涉及的数据库对象的最新统计信息。

每当运行 UPDATE STATISTICS 查询时,以下系统编目表都会被刷新。每个标题下列出了表中的列。

  • 在 SYSTABLES 中
    • nindexes - 表中索引的数量
    • nrows - 表中的行数
    • npused - 用于存储 Tupule 的 ‘nrows’ 的页数
  • 在 SYSCOLUMNS 中
    • colmin - 列的次小值
    • colmax - 列的次大值
  • 在 SYSINDEXES 和 SYSFRAGMENTS 中
    • levels - B-树中的级数
    • leaves - B-树中包含的叶子的数量
    • nunique - 不同值的数量
    • clust - 与表相关的集群度
  • 在 SYSDISTRIB 中
    • 包含用户数据表的值的分布信息的行。(因此所有列都受影响)
    • 它还维护分布的分辨率和置信度

 

 

分辨率和置信度

要理解 UPDATE STATISTICS,需要掌握两个重要的术语:分辨率和置信度。分辨率 是指放入每个容器(bin)的数据所占的百分比。分辨率是介于 0.005 到 10 之间的一个数。置信度(Confidence) 用于度量所得估值与实际值之间的相似程度。它用一个介于 0.80 到 0.99 之间的值表示。理想情况下,置信度应该比较高。

对于 high 模式,默认的分辨率为 0.5,对于 medium 模式,默认的分辨率为 2.5。对于 high 模式,默认的置信度为 0.99。对于 medium 模式,默认的置信度介于 0.85 到 0.99 之间。

        有三种模式可用于更新统计数据:low、medium 和 high。

     low 模式 只填充表的标量统计值(也就是说,没有分布信息)。这种模式存储诸如 B-树索引的级数、表所占用的页数、一个列中不同值的数量之类的信息。

      在medium 模式 下,除了 low 模式下的统计信息外,该语句还存储一组列值样本,并将分布数据填充到表示该样本的 sysdistrib 系统编目表中。它的置信度通常介于 85% 到 99%。

high 模式 下,除了 low 模式下的统计信息外,该语句还对所有列值进行排序,并将执行时表中所有值上的确切分布信息填充到 sysdistrib 表中。看上去,以 high 模式使用 UPDATE STATISTICS 总是不错,然而事实并非如此。由于其分辨率只有 0.5,high 模式需要使用非常多的容器才能获得较高的准确性。因此,它需要消耗大量的磁盘空间,当表比较大时这一点尤为明显。而且,在连续运行的生成系统中,以 high 模式运行 UPDATE STATISTICS 显得过于密集。此外,high 模式并非总能保证得到完美的估计,因为既然计划是以估计为基础的,就不能保证执行计划是 100% 最优的。

 

 

Informix 使用直方图存储数据的分布信息。直方图用于计算谓词的选择率。它们被证明可以产生低误差的估计,并且几乎不占用运行时开销。

直方图以图形的方式总结和显示一个数据集的分布。Informix 使用带溢出桶(overflow bucket)的高度平衡直方图(即等高/等深),而不是宽度平衡直方图(等宽)。高度平衡意味着每个桶中的值的数量是相同的。根据这些值确定一个范围,一个桶代表一个范围。下面是直方图的一个例子:


直方图 

假设一个表中有 1000 行。如果桶的数量固定为 10,则比例为 1000/10;因此每个桶中有 100 行。这个 100 表示高度。当使用高度平衡直方图时,这个值(100)是固定不变的。

服务器为表中的各个列生成数据分布,这些数据分布被以编码直方图的形式存储在 sysdistrib 系统编目的 encdat 列中。如果列中的数据是均匀地分布在各个值域的,那么默认的容器数量可能就足够了。但是,如果数据高度歪斜,那么就需要更多的容器(更小的分辨率),以确保数据不会太歪斜。

UPDATE STATISTICS 的魔术

基本上,只要以 medium 或 high 模式运行 UPDATE STATISTICS 命令,都会创建两种类型的容器,即分布容器和溢出容器。容器中的每个条目由以下内容组成:

  1. 分布容器
    • 容器中的行数
    • 容器中不同值的数量
    • 容器中的最大数据值
  2. 溢出容器
    • 数据值
    • 数据值出现的频率

 

例子

现在,我们来考虑一个 Inventory 表,这个表由三个列组成 item_num、customer_name 和 amount。我们将在列 item_num 上执行 UPDATE STATISTICS,看看这两种容器是如何构造的。

表 1. Inventory 表

item_num customer_name amount 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 4 5
manoj 92.5
prasanna 43.75
bharath 90
ranjani 78.5
priya 23.5
radhika 126.75
vaibhav 75
harsha 300.50
vishwas 20
deepak 32.5
vinay 90
archit 65.20
vishnu 32.75
samir 48.3
ravi 49.5
srini 67.5
rahul 56.0
sudev 73.0


为了填充数据分布,以 medium 或 high 模式运行 UPDATE STATISTICS。可以通过调用以下命令,从 Informix 的实用程序 dbschema 中获得直方图信息:

$ dbschema -d <dbname> -hd [ <table> ]


在 medium 模式下采用分辨率 10 运行 UPDATE STATISTICS 时,以上数据的分布如下面的清单所示。


清单 1. 分布输出

                
$ dbschema -d newdb -hd Inventory

DBSCHEMA Schema Utility INFORMIX-SQL Version 11.10.FC2
Copyright IBM Corporation 1996, 2006 All rights reserved
Software Serial Number AAA#B000000

{

Distribution for informix.Inventory.item_num

Constructed on 2007-11-09 04:47:00.00000

Medium Mode, 10.000000 Resolution, 0.950000 Confidence


--- DISTRIBUTION ---

    (                     1)
 1: (  2,   2,            4)
 2: (  1,   1,            5)


--- OVERFLOW ---

 1: ( 9,                 1)
 2: ( 6,                 2)




理解分布容器

设置容器的数量

计算容器的数量的公式是:
100/分辨率 = 容器的数量
如果分辨率为 1,则意味着每个容器中包含 1% 的数据(100/1 = 100 个容器)。
如果分辨率为 10,则意味着每个容器中包含 10% 的数据(创建 10 个容器)。

容器总是以一个容器编号或标识符开始,这个容器编号或标识符是逐行递增的。每一行有 3 个列。所有这 3 个列都在括号中表示。第 1 列指定容器的大小。第 2 列指定当前范围中不同元素的数量,第 3 列指定当前范围中的最大值。

例如,考虑上面的 分布输出,第 1 行可以这样理解:

  • 容器大小 = 2
  • 在 1 到 4 之间有 2 个不同的元素。可以通过查看 Inventory 表 验证这一点。这两个不同的值是 3 和 4。真正细心的观察者可能已经注意到,分布容器中不包括 1 和 2 这两个值。这两个值的计数被放在溢出容器中,不在分布容器中。
  • 范围是 1 到 4。

 

理解溢出容器

和分布容器一样,溢出容器也是以行表示的。每一行以一个标识符开始,这个标识符也是逐行递增的。这种容器中只有 2 个列,都在括号中表示。第 1 列指定第 2 列中的值重复出现的次数。第 2 列指定列值本身。

例如,在上述表中可以看到, C1=1 重复了 9 次, C1=2 重复了 6 次。注意,只有那些超过容器大小的 25% 的列值被放入溢出容器中。这里获得的计数是绝对可靠的值,可用于估计。

注意:dbschema 的输出不能与常规的行和列的概念相提并论。这里的术语行和列只具有字面意义,与数据库中使用的行和列的概念没有关联。

查询计划的例子

考虑两个表:customerorders。customer 表有 customer_numzipcodecustomer_name 属性;orders 表有 customer_numquantityitem_num 属性。

通过下面的例子可以看到查询的查询计划是什么样子:

 select * 
from orders a, customer b 
where a.customer_num > 435 and b.zipcode > "65*" ;

当以 high 模式运行 UPDATE STATISTICS 时,结果如下:

清单 2. SQEXPLAIN 输出
                    
QUERY:
------
Completed pass 1 in 0 minutes 0 seconds

UPDATE STATISTICS:
==================

Table:          informix.customer
Mode:           HIGH
Number of Bins:      288        Bin size       11
Sort data            0.2 MB     Sort memory granted          0.2 MB
Estimated number of table scans 1
PASS #1 zipcode
Light scans enabled
Scan 0 Sort 0 Build 0 Insert 0 Close 0 Total 0
Completed pass 1 in 0 minutes 0 seconds
QUERY:
------
select * from orders a, customer b where a.customer_num > 435 and b.zipcode > "65*"

Estimated Cost: 9805
Estimated # of Rows Returned: 244530
Maximum Threads: 1

  1) informix.b: INDEX PATH

    (1) Index Keys: zipcode   (Parallel, fragments: ALL)
        Lower Index Filter: informix.b.zipcode > '65*'

  2) informix.a: INDEX PATH

    (1) Index Keys: customer_num   (Parallel, fragments: ALL)
        Lower Index Filter: informix.a.customer_num > 435
NESTED LOOP JOIN

没有 UPDATE STATISTICS 的情况

考虑一个典型的场景,这个场景可以演示 UPDATE STATISTICS 的重要性。考虑 3 个表:T1、T2 和 T3。假设它们分别有 10、100 和 1000 行。现在假设要在这 3 个表上执行一个 'EQUI-JOIN' 操作。在执行实际的连接操作之前,优化器使用统计数据制定一个查询计划。您假定这个统计数据是最新的,并继续后面的工作。

现在,有多少种方法可以用来执行这个连接操作?要知道,T1 * T2 与 T2 * T1 是不相同的,因此这是一个简单的排列问题。这里有 3 个表,因此有 3! * 2! * 1! 种方法来执行连接操作。也就是说,有 12 种不同的方法来执行这个操作。对于这个例子,只使用 12 种方法中的 5 种方法。

Case 1 -- (T1 * T2) * T3 导致 1,011,010 次行访问。
Case 2 -- (T2 * T1) * T3 导致 1,101,100 次行访问。
Case 3 -- (T1 * T3) * T2 导致 1,011,010 次行访问。
Case 4 -- T1 * (T2 * T3) 导致 1,001,010 次行访问。
Case 5 -- T3 * (T2 * T1) 导致 1,011,000 次行访问。

现在,假设发生了很多的事务,这些表都被操纵。现在,T1、T2 和 T3 将分别有 1000、100 和 10 个行。由于没有自动运行 UPDATE STATISTICS,所以 System Catalog 表没有更新,仍然保留旧的统计数据。现在,您应该再次执行 EQUI-JOIN 操作。

优化器选择 Case 4,因为它断定 Case 4 访问的行数最少,因而最高效。但是,这个计划不再产生最佳结果。根据当前的情况,高效的计划应该是使用 Case 5 — (T3 * (T2 * T1) — 而优化器却选择 Case 4 — T1 * (T2 * T3)。这导致访问的行数增加了 ‘9990’ 行。对于大的数据库,这个数字会上升到数万亿,这将大大降低查询的效率。但是,如果执行了 UPDATE STATISTICS 语句,那么效率就会高得多。这个例子表明为什么必须定期运行 UPDATE STATISTICS。

总之,应使用 UPDATE STATISTICS 来执行以下任何任务:

  • 计算列值的分布。
  • 更新数据库服务器用于优化查询的系统编目表。
  • 对 SPL 例程实行再度优化。
  • 更新数据库服务器时转换已有索引。

 

UPDATE STATISTICS 的语法

版本 1:用于整个数据库的 UPDATE STATISTICS

UPDATE STATISTICS [LOW | MEDIUM | HIGH];

版本 2:用于数据库中特定表的 UPDATE STATISTICS。在这种情况下,所有列都被更新。
UPDATE STATISTICS [LOW | MEDIUM | HIGH] FOR TABLE <table_name> ;

版本 3:用于数据库中特定表的特定列的 UPDATE STATISTICS。
UPDATE STATISTICS [LOW | MEDIUM | HIGH] FOR TABLE <table_name> (<column_name>);

版本 4:用于数据库中某个存储过程的 UPDATE STATISTICS。
UPDATE STATISTICS [LOW | MEDIUM | HIGH] FOR PROCEDURE;

版本 5:通过设置自己的分辨率执行 UPDATE STATISTICS。
UPDATE STATISTICS [LOW | MEDIUM | HIGH] FOR TABLE <table_name> RESOLUTION 10;

提示和技巧

UPDATE STATISTICS 命令不会自动执行。用户需要手动运行该语句。必须定期执行该命令,以便优化器利用最新的数据制定有效的计划来抓取数据。

当对数据库中的大量数据进行操纵时,最好运行该语句。默认情况下,UPDATE STATISTICS 以 low 模式运行。在这种模式下,不会生成数据分布。除非数据库或表的规模很小,否则不要对整个数据库、一个数据库中的所有表或一个表中的所有列使用 high 模式。
请务必牢记,对于文本列或字节列不会创建分布。

UPDATE STATISTICS FAQ

 

  • 用于 Update Statistics 命令的理想模式是什么?

    不存在所谓的 “理想” 模式。DBA 应该分析当前情况,然后选择 UPDATE STATISTICS 的模式。但是,下面的列表为帮助您选择最佳模式提供了一些提示:

    如果被更改的行数很多,或者刚在不同版本的数据库服务器之间完成迁移,则应使用 UPDATE STATISTICS LOW。对于不是索引起始列的所有列,也应使用该模式。
    仅当查询中有非索引连接列或过滤列时,才使用 UPDATE STATISTICS MEDIUM DISTRIBUTIONS。
    如果查询中有属于多列索引的连接列或过滤列,则使用 UPDATE STATISTICS HIGH <table>。
    如果查询中有很多小型的表(在一个盘区),则使用 UPDATE STATISTICS HIGH ON <small tables>。

  • 我在运行该语句时,可以自己设置分辨率和置信度吗?

    可以,设置的语法如下: UPDATE STATISTICS MEDIUM FOR TABLE <tabname> RESOLUTION 1 0.99-----> confidence

  • 我发现整个过程会消耗很多时间,占用很多资源。您不认为直接执行查询更好一些吗?

    我们应该牢记,在准备统计数据时,只考虑样本行,而不会读所有的行。因此,除非以 high 模式运行,否则 UPDATE STATISTICS 与执行查询本身是不能相提并论的。

  • 什么是理想的分辨率值?

    不存在所谓的 “理想的” 分辨率值。这个值完全取决于数据和应用程序。

  • 所有三种模式的默认分辨率和置信度是多少?

    对于 HIGH 模式,默认的分辨率为 0.5,对于 MEDIUM 模式,默认的分辨率为 2.5。
    对于 HIGH 模式,默认的置信度为 0.99,对于 MEDIUM 模式,默认的置信度介于 0.85 到 0.99 之间。

  • 在 Cheetah 中,这个特性有什么新变化?

    在 Cheetah (IDS 11) 中,当创建索引时,IDS 自动收集起始索引键上的索引统计信息。这样避免了手动执行统计信息收集命令。有了这个特性,查询优化器在确定访问计划时可以直接考虑索引。可以在 SET EXPLAIN 中新的 Query Statistics 区查看关于完成的查询的统计信息。 在使用 MEDIUM 模式的显式的 UPDATE STATISTICS 操作中,可以在 resolution 子句中使用新的 SAMPLING SIZE 选项为列分布抽样指定最小行数。SET EXPLAIN 语句现在支持一个可选的参数,该参数用于覆盖输出文件的默认名称和位置。

  • 在存储过程上执行 UPDATE STATISTICS 是什么意思?

    数据库服务器再度优化指定过程中的 SQL 语句。数据库服务器不更新系统编目表中的统计信息。

  • 当我将分辨率设为 0.5,置信度设为 0.99,并以 MEDIUM 模式运行 UPDATE STATISTICS 时,会发生什么情况?这是否等效于以 HIGH 模式运行该语句?

    是的。

  • 我最多可以使用多少个容器?

    理想情况下,分辨率是介于 0.005 到 10 之间的一个值。因此容器的数量介于 10 到 20,000 之间。但是基本上,容器的最大数量取决于磁盘空间和 IDS 施加的任何限制。

 

结束语

Informix Dynamic Server 是一种强大的数据库服务器,它具有很多强大的特性 — UPDATE STATISTICS 是其中一个重要的特性。如今,由于分秒之间就会发生数百万个事务,数据库极其多变,本文解释了这种情况下对 UPDATE STATISTICS 的需要。在处理数据库时,查询优化至关重要,而 UPDATE STATISTICS 正是用于此目的。UPDATE STATISTICS 并非一个完美的解决方案,重要的是 DBA 要有所权衡,根据当前情况选择尽可能最佳的解决方案。本文提供的信息可以帮助您以一种轻松得多的方式使用 UPDATE STATISTICS

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics