Oracel SQL优化器CBO optimizer 案例分析:星形转换

学完本课后,应能完成以下工作:

  • 定义星形方案
  • 展示没有转换的星形查询计划
  • 定义星形转换要求
  • 展示转换后的星形查询计划

 

星形方案模型

star-query-1

星形方案是最简单的数据仓库方案。之所以将其称作星形方案,是因为此方案的实体关系图类似于星形:多个点呈放射状围绕在中心表周围。星形的中心由一个或多个事实表组成,星形的点是维表。星形方案的特点如下:具有一个或多个非常大的事实表,这些表包含数据仓库中的主要信息,同时还具有许多较小的维表(或查找表),每个维表都包含有关事实表中某个特定属性的多项信息。星形查询是事实表和众多维表之间的联接。每个维表都使用主键联接到事实表的外键,但维表彼此之间没有联接。基于成本的优化程序 (CBO) 可识别星形查询,并为其生成高效的执行计划。事实表通常包含关键字和度量。例如,在销售历史方案中,sales 事实表包含 quantity_sold、amount 和 cost 度量以及 cust_id、time_id、prod_id、channel_id 和 promo_id 关键字。维表是 customers、times、products、channels 和 promotions。例如,products 维表包含事实表中的每个产品编号的信息。

注:可以很容易地将此模型扩展成包括多个事实表。

 

雪花方案模型

 

star-query-3

雪花方案是一种比星形方案更复杂的数据仓库模型,是星形方案的一种类型。之所以将其称作雪花方案,是因为此方案的关系图类似于雪花。雪花方案对维进行了规范化,以消除冗余。也就是将维数据划分到多个表中,而不是放在一个大表中。例如,在雪花方案中,星形方案中的产品维表在规范化后,可能变成一个 products 表、一个 product_category 表,以及一个 product_manufacturer 表,或如幻灯片所示,可以使用 countries 表来规范化 customers 表。虽然这样可节省空间,但增加了维表的数量,因此需要更多的外键联接。导致的结果是查询的复杂度增加,并且查询性能有所降低。

注:建议您优先选择星形方案,除非有明确的理由,否则不要选择雪花方案。

 

星形查询:示例

 

星形查询:示例
请考虑幻灯片中的星形查询。为了运行星形转换,假定销售历史方案的 sales 表在 time_id、channel_id 和 cust_id 列上有位图索引。

SELECT ch.channel_class, c.cust_city,  
       t.calendar_quarter_desc, 
       SUM(s.amount_sold) sales_amount 
 
FROM sales s,times t,customers c,channels ch 
WHERE s.time_id = t.time_id AND  
      s.cust_id = c.cust_id AND 
      s.channel_id = ch.channel_id AND  
      c.cust_state_province = 'CA' AND  
      ch.channel_desc IN ('Internet','Catalog') AND  
      t.calendar_quarter_desc IN ('1999-Q1','1999-Q2') 
 
GROUP BY ch.channel_class, c.cust_city,  
         t.calendar_quarter_desc; 

没有星形转换的执行计划

star-query-4

首先观察一下不进行星形转换的情况下星形方案中的联接的处理过程,然后再来了解此转换的优点。
幻灯片中计划的基本问题是查询总是启动 SALES 表到维表的联接。这会导致大量的行,这些行只能由执行计划中的其它父联接进行缩减。

星形转换

 

  • 在事实表外键上创建位图索引。
  • 将 STAR_TRANSFORMATION_ENABLED 设置为 TRUE。
  • 至少需要两个维表和一个事实表。
  • 收集所有相应对象的统计信息。
  • 执行过程分两个阶段:

–首先,基于维过滤器使用位图索引识别相关的事实行。

–将它们联接到维表。

 

要使星形查询获得尽可能高的性能,必须遵循一些基本准则:

  • 位图索引应构建在事实表或表的各个外键列之上。
  • STAR_TRANSFORMATION_ENABLED 初始化参数应设置为 TRUE。这会为星形查询启用一个重要的优化程序功能。为了实现向后兼容,其默认设置为 FALSE。

如果数据仓库满足这些条件,则在其中运行的大部分星形查询都会使用称为“星形转换”的查询执行策略。借助星形转换,星形查询可以具有很高的查询性能。

星形转换是一种功能强大的优化技术,该技术基于隐式重写(或转换)原始星形查询的 SQL。最终用户不需要了解星形转换的任何细节。系统的 CBO 会自动选择适合进行星形转换的地方。Oracle 处理星形查询的过程分两个基本阶段:

  • 第一阶段仅从事实表(结果集)检索必要的行。由于此检索利用了位图索引,因此非常高效。
  • 第二个阶段将此结果集联接至维表。此操作称为半联接。

注:查询中至少使用三个表(两个维表和一个事实表)。

星形转换:注意事项

  • 不会转换包含绑定变量的查询。
  • 不会转换引用远程事实表的查询。
  • 不会转换包含反联接表的查询。
  • 不会转换引用未合并的未分区视图的查询。

星形转换不适用于具有以下任一特征的表:

  • 查询具有与位图访问路径不兼容的表提示
  • 查询包含绑定变量
  • 表具有的位图索引过少。事实表列上必须有一个位图索引,优化程序才能为其生成子查询。
  • 远程事实表。但在所生成的子查询中可以有远程维表。
  • 反联接表。
  • 表已用作子查询中的维表。
  • 表实际上是未合并的视图,而不是视图分区。

 

星形转换:重写示例

系统分两个阶段来处理前面提到的查询。在第一阶段中,系统对维表使用过滤器,检索与过滤器匹配的维主键。之后系统使用这些主键来探测事实表外键列上的位图索引,以便仅识别和检索事实表中的必要行。即系统实际上使用幻灯片中经过重写的查询从 sales 表中检索结果集。
注:幻灯片中的 SQL 是理论上的 SQL 语句,用于表示在第一阶段发生的操作。

SELECT s.amount_sold 
FROM sales s 
 
WHERE time_id IN (SELECT time_id  
                  FROM times 
                  WHERE calendar_quarter_desc  
                      IN('1999-Q1','1999-Q2')) 
 
AND   cust_id IN (SELECT cust_id  
                  FROM customers  
                  WHERE cust_state_province = 'CA') 
 
AND channel_id IN(SELECT channel_id  
                  FROM channels  
                  WHERE channel_desc IN  
                            ('Internet','Catalog')); 


 

根据一个维表检索事实行

star-query-2

幻灯片显示了仅使用一个维表检索事实表行的过程。系统基于相应的维过滤谓词(类似于上一张幻灯片示例中的 t.calendar_quarter_desc IN (‘1999-Q1′,’1999-Q2’))扫描维表,针对每个相应行探测相应的事实表位图索引,获取相应的位图。

BITMAP KEY ITERATION 将其左侧输入的每个关键字作为右侧输入的索引的查找关键字,然后返回该索引获取的所有位图。请注意,在本例中左侧的输入提供了维表的联接关键字。

此树的最后一步将合并在以前步骤中获得的所有位图。此合并操作会生成一个位图,该位图可以表示事实表中与维表的相关行相联接的行。

注: 使用共享服务器模式时,BITMAP_MERGE_AREA_SIZE 在优化此操作性能上起到非常重要的作用。除非对实例配置了共享服务器选项,否则系统不建议使用 BITMAP_MERGE_AREA_SIZE 参数。系统建议您通过设置 PGA_AGGREGATE_TARGET 启用自动调整 SQL 工作区大小功能。保留 BITMAP_MERGE_AREA_SIZE 是为了实现向后兼容。

 

根据所有维表检索事实行

star-query-5

 

在第一阶段,针对各个维表重复上一幻灯片中提到的步骤。因此计划中的每个 BITMAP MERGE 会为一个维表生成一个位图。要从事实表中识别出所有相关的行,系统必须对生成的所有位图取交集。这样做是为了清除只与一个维表联接,但未与所有维表联接的事实行。这是通过对根据每个维表生成的所有位图执行非常高效的 BITMAP AND 操作实现的。最后生成的位图可以表示事实表中与维表的所有合格行相联接的行。

注:到现在为止,仅使用了事实表位图索引和维表。要进一步访问事实表,系统必须将生成的位图转换成行 ID 集。

 

将临时结果集与维表相联接

 

star-query-6

确定结果集之后,系统将进入星形转换算法的第 2 阶段。在此阶段,需要将与结果集对应的销售数据与用于对行分组且属于查询的选择列表的维表数据相联接。

请注意,幻灯片中的图显示了在事实表与其维表之间执行的散列联接。尽管从统计结果看,散列联接是最常用的一种联接星形查询中的行的技术,但可能并不总是如此,具体采用的技术由 CBO 评估。

 

星形转换计划:示例 1

star-query-7

 

此计划可以用来回答“没有星形转换的执行计划”部分中显示的查询。请注意,出于格式化方面的原因,仅显示了通道和时间维。可以很容易地将此案例扩展为 n 维。

注:假定 sales 没有分区。

 

星形转换:进一步优化

star-query-8

  • 在星形转换执行计划中,对维表进行了两次访问;每个阶段访问一次。
  • 如果维表很大,而选择率很低,这可能会造成性能问题。
  • 如果创建临时表的成本较低,系统可能会决定使用此方式,而不访问同一维表两次。
  • 在计划中创建临时表:

查看前面的执行计划时,您会发现每个维表都需要访问两次:
在第一阶段中,系统会访问一次维表来决定必要的事实表行;在第二阶段中,系统会再访问一次维表来将事实行与每个维表相联接。如果维表很大,且在访问这些维表时没有有助于解决问题的快速访问路径,则可能会造成性能问题。在此类情况下,系统可能会决定创建临时表,表中包含两个阶段所需的信息。如果创建一个由维表的谓词和联接列的结果集组成的临时表所花费的成本比访问维表两次的成本低,则系统会采用前一种方式。在前面的执行计划示例中,TIMES 和 CHANNELS 表很小,使用全表扫描对其进行访问的工作量并不是很大。

上面的执行计划显示了这些临时表的创建和数据插入方式。这些临时表的名称是系统生成的,并且不是固定的。幻灯片中显示了某执行计划的一部分,该执行计划对 CUSTOMERS 表使用了临时表。

注:另外,在下列情况下星形转换不使用临时表:

  • 数据库处于只读模式。
  • 星形查询所属的事务处理处于可串行化模式。

 

 

使用位图联接索引

 

  • 减少了要联接的数据量
  • 可以用于消除按位操作
  • 在存储方面比 MJV 效率高

 

CREATE BITMAP INDEX sales_q_bjx

ON sales(times.calendar_quarter_desc)

FROM sales, times

WHERE sales.time_id = times.time_id

 

如果用作联接的联接索引已预先计算好,则会减少需要联接的数据量。

另外,包含多个维表的联接索引可以消除按位操作,这些操作在使用现有位图索引的星形转换中是必不可少的。

最后,位图联接索引在存储方面比实体化联接视图 (MJV) 效率高,因为 MJV 不对事实表的行 ID 进行压缩。

后面假设您已创建了幻灯片中提及的附加索引结构。

 

星形转换计划:示例 2

 

SORT GROUP BY 
 HASH JOIN 
    HASH JOIN 
       TABLE ACCESS BY INDEX ROWID SALES 
         BITMAP CONVERSION TO ROWIDS 
          BITMAP AND 
           BITMAP MERGE 
            BITMAP KEY ITERATION 
             BUFFER SORT 
              TABLE ACCESS FULL CHANNELS 
             BITMAP INDEX RANGE SCAN SALES_CHANNELS_BX 
           BITMAP OR 
             BITMAP INDEX SINGLE VALUE SALES_Q_BJX 
             BITMAP INDEX SINGLE VALUE SALES_Q_BJX 
       TABLE ACCESS FULL CHANNELS 
    TABLE ACCESS FULL TIMES 

对同一星形查询使用位图联接索引进行处理的过程类似于前面的示例。唯一的区别是系统在星形查询的第一阶段使用联接索引,而不是单个表的位图索引来访问 times 数据。
此计划与上一计划的区别在于,在对 times 维做位图索引扫描的内部部分没有第 1 阶段的重写查询中的子选择语句。这是因为 times.calendar_quarter_desc 的联接谓词信息可从 sales_q_bjx 位图联接索引获取。
请注意,系统会访问联接索引两次,因为相应查询的谓词是 t.calendar_quarter_desc IN (‘1999-Q1′,’1999-Q2’)

 

星形转换提示

 

  • STAR_TRANSFORMATION 提示:使用包含星形转换的最佳计划(如果有)。
  • FACT (<table_name>) 提示:应将提示表作为星形转换上下文中的事实表。
  • NO_FACT (<table_name>) 提示:不应将提示表作为星形转换上下文中的事实表。
  • FACT 和 NO_FACT 提示对于包含多个事实表的星形查询很有用。

 

  • STAR_TRANSFORMATION 提示可使优化程序使用其中使用了转换的最佳计划。如果没有提示,优化程序可能会基于成本作出决定,使用已生成的没有转换的最佳计划,而不使用已转换查询的最佳计划,即使给出提示,也不能保证转换一定会发生。优化程序仅在适当情况下生成子查询。如果没有生成子查询,则没有转换的查询,此时不管是否有提示,都使用未转换查询的最佳计划。
  • FACT 提示在星形转换上下文中使用,用于指示转换时应将提示表作为事实表,其它所有表无论大小都作为维表。
  • NO_FACT 提示在星形转换上下文中使用,用于指示转换时不应将提示表作为事实表。

注:仅当星形查询要访问多个事实表时,才可能用到 FACT 和 NO_FACT 提示。

 

位图联接索引:联接模型 1

star-query-9

CREATE BITMAP INDEX bji ON f(d.c1)  

FROM f, d  

WHERE d.pk = f.fk;

SELECT sum(f.facts)

FROM d, f

WHERE d.pk = f.fk AND d.c1 = 1;

 

在接下来的三张幻灯片中,F 代表事实表,D 代表维表,PK 代表主键,FK 代表外键。

位图联接索引可以在幻灯片所示的 SELECT 语句中使用,用于避免联接操作。

位图联接索引类似于实体化联接视图,它预先计算联接,并将其存储为数据库对象。二者之间的区别在于:实体化联接视图会使联接实体化为一个表,而位图联接索引会将联接实体化成一个位图索引。

注: C1 是维表中的索引列。

 

 

位图联接索引:联接模型 2

star-query-10

本幻灯片中的模型是模型 1 的扩展形式,需要使用级联位图联接索引来表示。

请注意,本例中的 BJX 也可以用来回答下列选择语句:

select sum(f.facts) from d,f where d.pk=f.fk and d.c1=1

这是因为 D.C1 位于 BJX 的第一部分。

 

 

位图联接索引:联接模型 3

star-query-11

此模型也需要使用幻灯片中所示的级联位图联接索引。在本例中使用了两个维表。

位图联接索引:联接模型 4

star-query-12

本幻灯片显示了在两个或更多维表之间存在联接的雪花模型。可以用位图联接索引来表示它。位图联接索引可以是单个的,也可以是级联的,具体取决于维表中用于索引的列的数量。可以在 D1.C1 上创建一个位图联接索引,在 D1 和 D2 之间以及 D2 和 F 之间建立联接,如幻灯片中的 BJX 所示。

 

 

Comment

*

沪ICP备14014813号

沪公网安备 31010802001379号