【问题标题】:different columns on select query results different costs选择查询结果的不同列不同的成本
【发布时间】:2013-08-29 22:14:48
【问题描述】:

在表 invt_item_d(item_id & branch_id & co_id) 列上有一个索引。 第一个查询的计划结果是TABLE ACCESS FULL,成本是528, 第二个查询的结果是INDEX FAST FULL SCAN(我的索引),成本是27

如您所见,唯一的区别是,所选列用于第二个查询的索引。

这有什么问题吗?请问,您能告诉我我应该怎么做才能在 db 管理级别解决这个问题吗?

select d.qty
  from invt_item_d d 
 where d.item_id = 999 
   and d.branch_id = 888 
   and d.co_id = 777

select d.item_id
  from invt_item_d d 
 where d.item_id = 999 
   and d.branch_id = 888 
   and d.co_id = 777

编辑: 我做了一个新查询,这个查询的成本是 529,TABLE ACCESS FULL。

select qty from invt_item_d

所以我是否使用索引都没有关系。有人说这很正常,这真的是正常行为吗?

【问题讨论】:

    标签: performance oracle indexing


    【解决方案1】:

    在第一种情况下,必须访问表,因为“数量”列只存储在表中。

    在第二种情况下,查询中使用的所有列都可以从索引中读取,完全跳过表读取。

    您可以在列(item_id、branch_id、co_id、qty)上添加另一个索引,它很可能会在第一个查询中使用。

    来自 Oracle 文档:http://docs.oracle.com/cd/E11882_01/server.112/e25789/indexiot.htm

    快速全索引扫描是一种全索引扫描,其中数据库 访问索引本身中的数据而不访问表,并且 数据库不按特定顺序读取索引块。

    在以下情况下,快速全索引扫描是全表扫描的替代方法 满足以下两个条件:

    • 索引必须包含查询所需的所有列。

    • 包含所有空值的行不得出现在查询结果集中。为保证这一结果,在 索引必须有:

      • NOT NULL 约束

      • 应用于它的谓词,防止在查询结果集中考虑空值

    【讨论】:

    • @leitmotif 第一个答案已经是正确答案(恕我直言),你为什么忽略它?
    • 因为 where 子句的所有列都存在于索引中。 index 不适合您选择的内容,不适合您过滤的内容。所以,这不是一个正确的答案
    • @leitmotif - 你错了。索引中的列也可用于您选择的内容。如果索引中已经存在所有数据,则无需访问该表。
    • 是的,你是对的,但这不是索引的主要工作。那么,您是否建议“为每个选定的列创建索引”?
    • 正如我在此处的另一条评论中提到的,我创建了另一个名称不同、结构相同的表。该查询在该表上运行良好。我还是不明白。我还执行了收集统计信息等
    【解决方案2】:

    这正是使用索引的主要目的——使搜索更快。 与查询没有索引的列相比,查询有索引的列更快。

    它的基本预言知识。

    【讨论】:

    • 我认为在 where 子句中使用带有索引的列时,索引很重要。
    • 无论如何我想我误解了 TABLE ACCESS FULL 是什么。如果是全表扫描会很糟糕
    • TABLE ACCESS FULL 意味着将扫描、比较整个表(每一行)并返回匹配的行。如果表非常大(几百万行),查询的性能会受到影响,即需要更多的时间来执行。然而,使用更少的行(比如几千行),这并不重要。我认为您是对的,当具有索引的列位于 where 子句中时,索引很重要。但是由于某种原因,您的第一个查询没有命中索引,但您的第二个查询是。
    • 好的,我明白了。我没有命中索引,因为有 34000 行,而不是数百万行。但是这个查询在一个循环中被命中 4000 次,它减慢了这个过程。我想我无能为力,对吧?
    【解决方案3】:

    我正在添加另一个答案,因为它似乎更方便。

    首先: “我没有命中索引,因为有 34000 行,而不是数百万行”。这是完全错误的,也是危险的理解。

    我的意思是,如果有几千行,并且索引没有命中(oracle 引擎执行全表扫描(TABLE ACCESS FULL)那么),这没什么大不了的。 Oracle 的速度足以在一秒钟内读取几千行(即使没有索引),因此您不会感觉到差异。查询仍然较慢(比有索引的情况),但它是如此之少慢到你不会感觉到差异。 但是,如果有数百万行,那么在没有索引的情况下,查询的执行会慢很多(因为这次它将在全表扫描中扫描数百万行)并且您的性能会受到影响。

    第二:为什么你必须循环一个有 34000 行的表,也就是 4000 次??? 那是一种可怕的做法。尽可能避免循环。必须有更好的方法!

    第三: 您可以使用索引提示强制 oracle 优化器命中索引。您需要知道索引的名称。

    select /*+ index(invt_item_d <index_name>) */
           d.qty
      from invt_item_d d 
     where d.item_id = 999 
       and d.branch_id = 888 
       and d.co_id = 777
    

    这是关于索引提示的堆栈溢出问题的link

    【讨论】:

    • 我试图强制查询使用索引,但它返回的结果更差。然后我创建了另一个具有相同结构和索引的表,并将所有 34000 行插入到新表中。然后当我用新表运行查询时,结果更好(成本= 250)。之后我认为问题出在统计信息上,为 invt_item_d 表和索引执行了收集统计信息,但我仍然没有得到更好的结果,即使它变得更糟了(成本是 528,现在是 550)
    猜你喜欢
    • 1970-01-01
    • 2018-11-22
    • 1970-01-01
    • 2022-08-10
    • 2011-11-10
    • 1970-01-01
    • 2021-06-19
    • 1970-01-01
    • 2021-10-27
    相关资源
    最近更新 更多