【问题标题】:ORACLE SQL INDEX PERFORMANCEORACLE SQL 索引性能
【发布时间】:2016-04-02 12:45:46
【问题描述】:

假设我们有以下查询:

select name
from friends
where upper(name) like UPPER('%ESC%') and age = 20;

索引它的最佳方法是什么?

  1. CREATE INDEX fr ON friends (AGE,UPPER(NAME));
  2. CREATE INDEX fr ON friends (AGE);

谢谢。

【问题讨论】:

    标签: sql oracle indexing


    【解决方案1】:

    最好的方法是什么?两者几乎是等价的,尽管第一个对于查询的优势可能很小。

    在较高级别上,您只能索引age,因为like 模式以通配符开头。因此,当age 是索引的第一列时,Oracle 可以使用该索引来查找所有年龄合适的人。

    一个小警告。如果您有第一个索引,Oracle 可能足够聪明,不会应用 upper(name) 函数,因为该值已经在索引中。 Oracle 仍需要扫描索引中的所有条目以查找age = 20,但它不需要转到where 子句的数据页。这可能是一种节省——但通常不会是一个很大的节省。

    如果查询是:

    where upper(name) between 'ESC' and 'FSC' and age = 20;
    

    那么第一个索引会更好,因为Oracle可以直接在索引中查找适当的行。

    【讨论】:

      【解决方案2】:

      可能这两个索引都无法帮助您完成此查询。

      AGE 似乎很有选择性。只有一百多个不同的值(假设我们可以排除树木和建筑物作为朋友)。因此,似乎对 AGE 的搜索正在寻找所有可能记录的约 1%。但是,AGE 分布并不均匀:AGE=20 上的过滤器返回的记录可能比 AGE=99 多得多。

      至于 UPPER(NAME),您对 like UPPER('%ESC%') 进行了限制。 CESC 将与 ESCOBAR 和 FRANCESCA 匹配。因此查询必须评估AGE=20 所在的每个名称。如果您在friends (AGE,UPPER(NAME)) 上有一个索引,则可以使用索引范围扫描评估整个 WHERE 子句,这将是相当有效的。 AGE 上的索引此时会导致表读取。

      无论哪种方式,查询都需要读取表来获取整个记录,因为您要返回NAME 而不是UPPER(NAME)。如果您在AGE=20 上获得很多点击,因为一个通用名称元素会包含很多索引读取,这很昂贵。除非 FRIENDS 是一个非常宽的表(很多列),否则读取整个表的全表扫描可能会更有效。

      性能调优是一个权衡问题。如果您在 FRIENDS 中有很多记录并且年龄分布很好并且您想在 AGE 和 UPPER(NAME) 上查询很多,那么 friends (AGE,UPPER(NAME)) 上的索引可能值得维护开销它。但是,如果它是一张小桌子或者你所有的朋友都是大学年龄,那么你很可能不应该为任何索引而烦恼。

      简而言之,这里有很多变数:您所能做的就是对各种选项进行基准测试,看看哪些最适合您。

      【讨论】:

        猜你喜欢
        • 2010-10-29
        • 1970-01-01
        • 2013-09-26
        • 2011-11-04
        • 1970-01-01
        • 1970-01-01
        • 2013-04-23
        • 1970-01-01
        • 2016-05-30
        相关资源
        最近更新 更多