【问题标题】:Oracle composite index for range query conditions范围查询条件的Oracle复合索引
【发布时间】:2012-05-14 05:42:01
【问题描述】:

我有一张桌子 Blah(纬度浮动,经度浮动,create_time 日期,owner_id int ......)

我的代码只做一个查询

select * 
from Blah 
where latitude < l1 and latitude > l2   
and longitude < ll1 and longitude > ll2   
and create_time < t1 and create_time > t2 
and owner_id < o1 and owner_id > o2 ;

(当然值 l1, l2,.... o1,o2 是来自程序的动态参数)

我的问题是我应该创建什么样的索引;综合指数? 如果是复合索引,我应该先放哪一列? 指数效果如何?

这个问题我想了很久,没找到关于oracle索引如何工作的详细文档。

我可以找到使用 B-tree 实现的文档,在我们的例子中:B-tree 中的每个键都是一个 4 元组:(column1,column2,column3,column4)其中定义了这些元组的排序关系是词汇顺序。

那么对于上面的查询,假设我们的顺序是(owner_id, create_time, latitude, longitude),我猜 oracle首先需要对点进行二分查找(​​o1,t1,l1,ll1),对于这个操作,索引确实很有用。 但是接下来,我们需要找到第一个中间体的终点:我们需要找到 (o1,t1, l1, ll2 ),这也可以通过二分查找来完成。

接下来,我们需要找到满足条件的下一段,所以我们需要 find (o1, t1, lx, ll1 ) 其中 lx 是下一个大于 l1 的值,我们也可以通过二进制搜索找到它。 但在我们的例子中,很可能对于相同的纬度,经度不能超过 1 个, 所以这里的二分查找并不比线性扫描更有效。

按照这个精神,看来我们应该把值域基数小的列放在前面, 在这种情况下,如果我们的积分仅在几天内创建,则为 create_time。 另外,如果我们从不做范围条件,而只做等于 (=) 条件,那么哪一列排在第一位并不重要,对吧?

为了更清楚,这里有一个更简单的例子:

假设我有 2 列,X 和 Y

在数据库中,两者的值都是 [1,2,....100],所以我们有 100x100 行

我的查询是

select * from mytable where X > 34 and X < 78 and Y > 12 and Y < 15;

假设我们的索引在 (X, Y) 上,那么两个值之间的比较规则是

v1 < v2 <=====>  v1.x < v2.x || v1.x == v2.x && v1.y < v2.y

给定上面的排序规则,我们可以看到索引中的值是 按顺序排列(x,y 的值):

1,1, 1,2 1,3 .... 1,100     
2,1  2,2 2,3 ......2,100
.....
100,1 100,2 ....... 100,100

现在,要在查询中搜索值,B-Tree 遍历需要 定位 (78-​​34-1) 间隔,因此 (78-​​34-1)*2 查找(1 为开头 一个用于结束位置),而不仅仅是 2 个查找。

所以如果我们有更高的维度,间隔计数会成倍增加 随着维度的数量,索引可能不再有用------ 这是我的担心

非常感谢 杨

【问题讨论】:

    标签: oracle optimization indexing composite-index


    【解决方案1】:

    一个简单的蛮力解决方案是在同一个表上创建多个索引组合,在打开EXPLAIN PLAN 的情况下运行查询,然后选择您的 DBMS 喜欢使用的索引。

    【讨论】:

      【解决方案2】:

      恕我直言,最好在标准 B 树索引之外处理多维范围查询。通过“多维范围查询”的网络搜索可以找到一些关于一般主题的论文。

      Oracle 提供了一个名为 Oracle Spatial 的产品。该产品的文档在Chapter 4 中包括创建空间索引和执行查询的示例和说明。没有新的 SQL 语法;他们创建索引的例子是:

      CREATE INDEX territory_idx ON territories (territory_geom)
          INDEXTYPE IS MDSYS.SPATIAL_INDEX;
      

      创建一个 R-tree 索引。

      我认为 R-trees、kdb-trees 和类似空间结构的存在证明了标准 B-trees 可能不适合这些类型的应用程序。

      【讨论】:

        【解决方案3】:

        此表是用于 OLTP 还是用作 DWH? 如果此表上没有很多单行/多线程 DML 语句,则可以使用位图索引。 位图索引允许您在多个索引之间进行 ROWID AND 运算符(也称为星形转换)。为了做到这一点,在每一列上创建一个位图索引。 就像我说的那样,这个解决方案最适合你有一个批量插入的 DWH 系统。

        【讨论】:

          【解决方案4】:

          首先,请记住“B-Tree”中的“B”不是“二进制”。

          其次,在 Oracle 中建立索引时,您还可以选择位图索引,如果:

          1. 您拥有企业版许可证
          2. 您没有多个会话同时修改表
          3. 您的索引值并不接近唯一(位图索引仅可用于低基数列的说法通常被夸大了)

          位图索引擅长的一种查询是有效地组合多列上的谓词,尤其是在谓词列集变化的情况下(当然,您可能不是这种情况)。如果满足以上三个条件,那么在表格上设置四个单独的位图索引的效果值得测试一下。

          【讨论】:

          • 谢谢,不过我现在只关心B-tree索引的问题;尽管实际上 Oracle 可能会使用位图索引,正如您所指出的那样
          【解决方案5】:

          如果您的唯一目标是创建一个索引来优化此查询,您希望复合索引中的列首先按照最有选择性的列进行排序。如果latitude 上的谓词比其他谓词消除了更多的行,那么首先拥有该列会更有效。如果owner_id 上的谓词比其他谓词消除了更多的行,那么首先拥有该列会更有效。

          但实际上,我们很少创建仅用于优化单个查询的索引。通常,为了使索引维护的开销值得,我们希望我们的索引在许多查询中都是有用的。在复合索引的情况下,这意味着按查询在该列上具有谓词的概率对列进行排序。例如,如果您在owner_id, create_time, latitude, longitude 上有一个复合索引,则可以将它用于仅在owner_id 上指定谓词的查询。但实际上,您不会将该索引用于仅在 longitude 上指定谓词的查询。

          【讨论】:

            猜你喜欢
            • 2022-12-12
            • 2020-10-24
            • 1970-01-01
            • 2011-08-21
            • 2017-03-05
            • 1970-01-01
            • 2021-03-31
            • 1970-01-01
            • 2018-03-27
            相关资源
            最近更新 更多