【发布时间】: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