添加索引后查询的性能下降

时间:2009-10-15 11:11:10

标签: sql performance oracle10g

我有一个查询SP的哪一部分定期执行,查询需要一段时间才能执行,所以我决定查看它。我对查询进行了自动跟踪,this was the execution计划返回[由于尺寸过大而粘贴在pastebin中]

我在正在进行全表访问的表上添加了索引,并运行了查询。尽管有cost being significantly lower,但查询性能比以前更差。

为什么会这样,有人可以对此有所了解吗?

数据库是Oracle 10gR2(版本10.2.0.1.0)。

这是正在运行的查询

SELECT DISTINCT CAC_FLEX_03, CAC_FLEX_04
        FROM PCOM_CUST_PRACTICE_INFO A,
             PGIM_ZIP_CODES          C,
             PGIM_PROD_TARIFF_DATA   B,
             PCOM_CODES_APPL_CODES   D
       WHERE A.PCPI_CUST_CODE IN ('002023', '002025')
         AND C.ZC_ZIP_CODE = A.PCPI_PIN_CODE
         AND C.ZC_CITY_CODE = A.PCPI_CITY
         AND C.ZC_COUNTY_CODE = A.PCPI_COUNTY
         AND C.ZC_STATE_CODE = A.PCPI_STATE
         AND B.PTD_CVR_CODE = 'TF-001'
         AND B.PTD_VALUE_SET2 = A.PCPI_STATE
         AND B.PTD_VALUE_SET4 = A.PCPI_COUNTY
         AND B.PTD_VALUE_SET5 = D.CAC_FLEX_03
         AND D.CAC_FLEX_04 IS NOT NULL
         AND ZC_STATE_CODE =
             (SELECT POL_FLEX_04
                FROM PGIT_POLICY
               WHERE POL_SYS_ID = 541332)
         AND B.PTD_VALUE_SET3 =
             (SELECT POL_FLEX_01
                FROM PGIT_POLICY
               WHERE POL_SYS_ID = 541332)
         AND CAC_TYPE = 'TERR-CODE'
         AND CAC_FLEX_03 = 0;

7 个答案:

答案 0 :(得分:4)

一些事情:

首先,如果访问超过一半的数据块,则完全扫描会更快,因为读取索引块是另一个IO调用,因此读取索引行的时间通常是读取连续行的两倍。

其次,你需要在有和没有索引的情况下查看你的计划。这里将提供信息,让您知道改变了什么。如果你看到“Merge Join Cartesian”,那么规划师就会出错。那个计划永远不会好。完全扫描的内部循环具有相同的IO成本,但占用的内存和临时空间更少。

第三,你使用ANALYZE TABLE构建了统计数据。别。即使是甲骨文也说它很糟糕而且很糟糕。使用dbms_stats包来构建统计数据,您将获得更准确的统计数据。如果仍然是奇数,请更改样本量,或者使用完整统计数据而不是估计值。

答案 1 :(得分:2)

我看到在索引表很小的情况下,查询会变慢。查询计划从构造临时哈希表变为使用(基于树)索引,该索引较慢(但会更好地扩展)。基于成本的优化工具并不总是能够使用可用的统计数据,如果您考虑它,实际上它是不可能的。对于足够复杂的查询计划,如果不进行查询,就不可能完美地预测性能。

答案 2 :(得分:1)

仅仅是为了感兴趣,查询中真的需要表PGIM_ZIP_CODES吗?在我看来,将“AND ZC_STATE_CODE =”[sql的第16行]更改为“和A.PCPI_STATE =”允许您从查询正文中删除PGIM_ZIP_CODES。

其次,看起来在PGIM_PROD_TARIFF_DATA上创建的索引无法正常完成工作 - 在我有限的经验中,只有78k行的表通常比表扫描更快,除非添加的索引是唯一的或者将该表的计划减少到仅索引查找(第二个计划看起来像是在表上创建了2个索引,并且它们不是唯一的。)

第三,现在我看起来有点难了。您的查询似乎可以解析为:

选择不同的CAC_FLEX_03,CAC_FLEX_04

来自PCOM_CODES_APPL_CODES

其中CAC_FLEX_03 = 0

和CAC_TYPE ='TERR-CODE'

哪里存在(等等等等)

  • 总是假设where存在是必需的 - 因为表A,B和C中存在一个结果行确实将返回表D中的所有行,其中CAC_FLEX_03 = 0且TYPE ='TERR-CODE'

PS我有没有误解这个问题!

答案 3 :(得分:0)

我们遇到了类似的问题,结果证明该指数是碎片化的。让您的DBA检查您正在使用的索引的所有统计数据,并查看是否需要重建。

请记住,在线重建会让你停留一段时间,但可能需要在某个时候进行离线重建。

答案 4 :(得分:0)

通过添加新索引,不会对“ 应该 ”产生负面影响。只有编写操作(需要修改索引)才能通过索引的存在减慢速度)即使是具有碎片的索引也应该比没有索引更快。如果你刚刚添加了索引,它就是全新的(或多或少),不应该被分割到任何明显的程度。除此之外,你说成本数字较低,我怀疑你在这里发生了与索引无关的其他事情。是否有可能某些其他事务可能暂时将查询锁定放在查询所需的某些数据行上并在一段时间内阻止它?

答案 5 :(得分:0)

与Charles Brentana所说的类似,添加索引不应该降低查询的性能。

如果所有统计信息都是最新的,那么基于成本的优化器会选择一个好的执行计划。同样,请仔细检查表格和索引的统计数据。

如果那里的一切都是犹太人,我只能假设还有其他因素会影响查询的性能。 DB服务器上是否还有其他负载(长时间运行的批处理作业,备份等),因此查询运行时间更长?您在查询中使用的其中一个表上是否有重大更新活动?数据是第一次在数据库缓存中,但不是第二次?我不知道你怎么能并排测试这两个陈述,但这种奇怪的行为必须有一些原因......

答案 6 :(得分:0)

您需要注意,基于成本的优化器虽然非常复杂且大部分时间都是正确的,但有时可能会出错。

有大量Oracle特定文献(例如参见Tom Kyte的博客)清楚地证明添加索引实际上可以降低SELECT语句的性能。除了其他原因之外,如果数据密度足够高,通过索引访问数据集可能比通过完全扫描进行数据集更昂贵。

有时您可以通过为所涉及的列生成直方图来使基于成本的优化器了解数据分布,但即使这样也有时会失败。我首先尝试为索引列生成直方图,如果失败,那么我们将不得不再次查看您的语句和访问计划。