Oracle:我怎样才能找到表空间碎片?

时间:2012-03-20 11:42:54

标签: sql oracle optimization query-optimization

我在两张桌子之间加入了。它真的很慢,我找不到原因。 查询在非常大的客户端上的PRODUCTION环境中需要数小时。 你能问我需要了解为什么它不能正常工作吗? 我可以添加索引,对表进行分区等等。它是Oracle 10g。 我期待几千条记录。由于以下条件: f.eif_campo1!= c.fornitura AND和f.field29 ='新' 事实上,应始终对所有1800万条记录进行验证

  SELECT    c.id_messaggio
           ,f.campo1 
           ,c.f
    FROM   
           flows c, 
           tab f
   WHERE   
               f.field198                  =  c.id_messaggio 
           AND f.extra_id      =  c.extra_id
           and f.field1                    != c.ExampleF
           and f.field29                   =  'New'
           and c.processtype         in ('Example1')
           and c.flag_ann                  =  'N';

以下记录的选择性表示为不同值的数量:

 COUNT (DISTINCT extra_id)                      =>17*10^6, 
 COUNT (DISTINCT (extra_id || field20))    =>17*10^6, 
 COUNT (DISTINCT field198)                                  =>36*10^6, 
 COUNT (DISTINCT (field19 || field20))                =>45*10^6, 
 COUNT (DISTINCT (field1))                                  =>18*10^6, 
 COUNT (DISTINCT (field20))                                =>47

这是执行计划[见大图] [1] ![在此处输入图像说明] [2]


额外详情: 我放松了一个记录,看看有多少记录。 30万。

![在此处输入图像说明] [7]

- 03:57分钟并行执行/ * +并行(c 8)并行(f 24)* /

- 395.358行

  SELECT     count(1)
    FROM   
           flows c, 
           flet f
   WHERE   
               f.field19                  =  c.id_messaggio 
           AND f.extra_id      =  c.extra_id
           and f.field20                  =  'ExampleF'
           and c.process_type         in ('ExampleP')
           and c.flag_ann                  =  'N';

2 个答案:

答案 0 :(得分:1)

简单的答案似乎是你的解释计划。您正在访问两个表by index rowid。虽然选择一行你不能 - 据我所知 - 变得更快,在你的情况下,你选择的不仅仅是一行。

这意味着,对于每一行,您一次只能进入两个表,当您查看表或索引的很大一部分时,这不是您想要做的。

我的建议是强制你的一个或两个表full scan。首先尝试使用较小的驱动程序:

SELECT /*+ full(c) */ c.flh_id_messaggio
     , f.eif_campo1 
     , c.f
  FROM flows c, 
  JOIN flet f
    ON f.field19  =  c.flh_id_messaggio
   AND f.extra_id =  c.extra_id
   AND f.field1 <> c.f
 WHERE ...

但您可能需要将/*+ full(c) */更改为/*+ full(c) full(f) */

您的索引似乎也是单独的列索引。为此,如果可能的话,我会有索引:

  • flows id_messaggio, extra_id, f
  • flet的{​​{1}}上

如果您不使用全扫描,这才真正重要。或者,如果您拥有所有返回的内容并且选择在一个索引中。

答案 1 :(得分:1)

您的解释计划显示以下内容。

  1. 数据库使用索引从ENI_FLUSSI_HUB中检索行 flh_tipo_processo_cod in ('VT','VOLTURA_ENI','CC')
  2. 然后它赢了行 其中flh_flag_ann = 'N'
  3. 这会生成一个用于访问的结果集 来自ETL_ELAB_INTERF_FLAT的行,基于f.idde_identif_dati_ext_id = c.idde_identif_dati_ext_id
  4. 最后根据这些行过滤这些行 WHERE子句的其余部分。
  5. 现在,如果flh_tipo_processo_cod是选择性的,那么起点很好 column:即,如果它包含数百个不同的值,或者是否包含值 你的清单比较少见。它甚至可能是标志列的好路径 标识相对较少的列,其值为“N”。所以你需要了解 数据的发布 - 您拥有多少不同的值 - 及其数据 倾斜 - 哪些值经常出现或几乎不出现。整体而言 表现表明,分布和/或倾斜 flh_tipo_processo_codflh_flag_ann列并不好。

    那你能做什么?一种方法是遵循Ben的建议,并使用完整 表扫描。如果您拥有Enterprise Edition许可证和足够的CPU容量 你可以尝试并行查询来改进。这可能仍然太慢,或者对其他用户来说可能太具破坏性。

    另一种方法是使用更好的索引。综合指数 eni_flussi_hub(flh_tipo_processo_cod,flh_flag_ann,idde_identif_dati_ext_id, flh_fornitura,flh_id_messaggio)可以避免阅读该表格。是否 这将是一个新的索引或ENI_FLK_IDX3的替代取决于另一个 针对桌子的活动。您可能可以从索引压缩中受益。

    查询投影中的所有列都在WHERE子句中引用。所以 您还可以在另一个表上使用复合索引以避免表读取。您需要了解Agsin数据的分布和偏差。但你可能应该选择排名最低的列。像etl_elab_interf_flat(etl_elab_interf_flat,eif_campo200,dde_identif_dati_ext_id,eif_campo1,eif_campo198)这样的东西。可能这是一个新的指数。您不太可能希望用此替换ETL_EIF_FK_IDX4(特别是如果它确实是外键约束的索引)。

    当然,这些只是我的猜测。调整是一门科学,正确地完成调整需要大量数据。使用the Wait Interface来调查数据库花费时间的位置。使用the 10053 event了解优化程序为何做出选择。但最重要的是,除非你真的知道后果,否则不会实现分区