解释计划显示使用分析函数和不同的查询所需的15 Exabyte空间量

时间:2012-11-20 18:10:08

标签: sql oracle optimization query-optimization sql-execution-plan

附件是fiddle,它在每个表的旁边放置我的模式,并在每个表中指示行数。查询看起来像是这样,以防小提琴被阻止:

select distinct cat_name,cat_age, co_cat_owners_id,cat_weight,cs_is_alive,os_is_current, cos_is_current,
      sum(cat_age) over(partition by co_cat_owners_id) running_total
from
   (
         select co.cat_owners_id co_cat_owners_id,
               co.cat_id co_cat_id,
               co.owner_id co_owner_id,
               co.vet_id co_vet_id, 
               cos.is_current cos_is_current,
               os.is_current os_is_current,
               cs.is_alive cs_is_alive,
               cat.name cat_name,
               cat.age cat_age,
               cat.weight cat_weight
         from cat_owners co,
              cat_owner_statuses cos,
              cat_statuses cs,
              cats cat,
              owners o,
              owner_statuses os
         where o.owner_id = co.owner_id
         and cat.cat_id = co.cat_id
         and cos.last_visit >= sysdate - 4/24
    )
where cs_is_alive = '1' 
and (cos_is_current = '1' OR os_is_current='1')
group by cat_name,cat_age,cat_weight,cs_is_alive,os_is_current,co_cat_owners_id,cos_is_current;

在我的开发环境中,解释计划在步骤方面非常接近于小提琴中的内容,但是我确实有几个步骤,其中内存大小为15E(exabytes),行数为4000P(petabytes)。我的问题是,在创建索引/错误SQL的过程中,我设法为一个问题生成15 exabyte解决方案,这个问题应该可以在更少的空间和时间内解决。我注意到调整一些复合索引创建步骤会产生稍微不同的结果,但我仍然被Exabyte空间要求阻止。

注意

如果将来某人没有阅读所有评论,则运行以下函数并结合正确的联接有助于:

analyze table table_name_here compute statistics;

3 个答案:

答案 0 :(得分:3)

您的查询在FROM子句中有6个表,但您只指定了两个连接条件。 OWNERS有1000万行,CAT_OWNERS有1.2亿行,所以我猜这个连接产生了1.2亿行。然后你加入到有{100}行的CATS,所以我假设你已经拥有了1.2亿行。但是,从那里,你没有更多的加入条件。因此,您的1.2亿行中间结果得到了笛卡尔与5亿行CAT_OWNER_STATUSES表的连接,该表生成1.2亿* 5亿行,即60万亿行。笛卡尔将其连接到1000万行CAT_STATUSES表,最终得到60万亿* 1000万行,现在我们达到了6 * 10 ^ 23行。然后你笛卡尔再次加入OWNER_STATUSES,它有9000万行,给你5.4 * 10 ^ 31行。如果您需要合理数量的结果,则需要指定其他连接条件以避免使用笛卡尔积。

遗憾的是,在您的小提琴中遵循数据模型有点困难,因为似乎有许多可能相互矛盾的方式将表连接在一起。 CAT_VETS将猫映射到兽医,但CAT_OWNERS也是如此。select distinct cat_name,cat_age, co_cat_owners_id,cat_weight,cs_is_alive,os_is_current, cos_is_current, sum(cat_age) over(partition by co_cat_owners_id) running_total from ( select co.cat_owners_id co_cat_owners_id, co.cat_id co_cat_id, co.owner_id co_owner_id, co.vet_id co_vet_id, cos.is_current cos_is_current, os.is_current os_is_current, cs.is_alive cs_is_alive, cat.name cat_name, cat.age cat_age, cat.weight cat_weight from cat_owners co, cat_owner_statuses cos, cat_statuses cs, cats cat, owners o, owner_statuses os, cat_vets cv, owner_vets ov where o.owner_id = co.owner_id and cat.cat_id = co.cat_id and cos.cat_owners_id = co.cat_owners_id and cs.cat_vets_id = cv.cat_vets_id and os.owner_vets_id = ov.owner_vets_id and ov.owner_id = o.owner_id and co.vet_id = ov.vet_id and co.vet_id = cv.vet_id and cos.last_visit >= sysdate - 4/24 ) where cs_is_alive = '1' and (cos_is_current = '1' OR os_is_current='1') group by cat_name,cat_age,cat_weight,cs_is_alive,os_is_current,co_cat_owners_id,cos_is_current; 如果没有数据和预期结果,就很难猜测表格应该如何连接。我的猜测是你需要像this modified fiddle

这样的东西
{{1}}

答案 1 :(得分:2)

由于您未使用连接语法,因此错过了将cat_statuses,cat_owner_statuses和owner_statuses的任何行与任何其余表连接在一起。这将导致每个表和连接表之间的交叉连接。这两个'状态'表包含多少行?

考虑加入每个表而不是用逗号列出它们,然后使用where过滤掉。我不确定SQL如何处理逗号分隔表(也可能是交叉连接) ...

     from owners o,
          join cat_owners co on o.owner_id = co.owner_id
          join cats cat on cat.cat_id = co.cat_id
          join cat_owner_statuses cos on XXXXX
          join cat_statuses cs on XXXXX,
          join owner_statuses os on XXXXX
     where cos.last_visit >= sysdate - 4/24

答案 2 :(得分:0)

您的几个表(例如cat_statuses)之间没有关系,因此产品联接会返回数以万计的行。也许您需要在您的小提琴示例中加入名为cat_vets的表格。

至少,您应该将外部where条件移动到派生表查询中;把它放在外面是没有效率的。