Oracle索引勉强加速汇总计算

时间:2018-09-11 21:46:45

标签: database oracle indexing

我创建了一个包含两列a和b的表。 a列只是数字1到1亿。 b列是介于0和999之间(含0和999)的随机整数。我想使用此表来检查索引如何改善计算。所以我检查了以下内容:

select count(*) from my_table where b = 332 

select avg(a) from my_table where b = 387

332和387只是随机整数,我想确保它没有缓存任何内容,所以我进行了切换。

然后我创建了一个索引:

create bitmap index myindx1 on my_table (b);
commit;

这使count(*)从14秒减少到75毫秒,成功了!

但是avg(a)表现不佳。实际上,情况变得更糟,从8秒变为10秒。我没有经过很多次测试,但根据计划,这似乎是fl幸,但至少看来它并没有像我期望的那样做得更好。

没有索引的说明计划如下:

explain plan without index

带有索引的说明计划如下:

explain plan with index

所以看起来有点帮助,但是平均数真的比计算它们贵吗?而且,与进行全表扫描相比,计算平均值要贵得多?我认为该索引会将查询减少到原始成本的一小部分,而不是仅仅节省一点时间。我还有其他方法可以加快查询速度吗?

谢谢。

2 个答案:

答案 0 :(得分:4)

问题在于您设置测试的方式-不现实,对索引不利。

首先:您的表中只有两个整数列,因此每一行都非常小。因此,Oracle可以在每个数据库块中容纳很多行,例如每个块中有几行数千行。

第二:您随机创建了索引数据 ,其值介于0到999之间。

将这两个事实放在一起,我们能猜到什么?答案:几乎每个每个数据库块将至少具有一行,列B具有给定值。

因此,无论您要寻找B的什么值,都将一次读取表中的每个块(即:“顺序读取”)。

将其与不使用索引的计划进行比较-全表扫描-Oracle仍将读取每个单个块,但它将一次读取多个块(即“分散读取”)。

难怪您的索引没有帮助。

如果您想要更好的测试,请将C列添加到测试表中,该列只是200-300个字符的字符串(例如,“ XXXXXXXXX ...”)。这样会将每个块的行数减少到更实际的值,并且应该从索引中看到更好的收益。

最后一个注意:使用BITMAP索引时要非常小心。它们几乎无法在具有各种DML(插入,更新,删除)的表上使用!使用它们之前,请先阅读所有有关它们的信息!

更新

对此进行澄清:

  
    

所以看起来有点帮助,但是平均数真的比计算它们贵吗?而且,平均数比进行全表扫描要贵吗?

  

您的索引帮助您的COUNT(*)查询的原因是,索引本身会告诉Oracle有多少行满足条件B=332,因此它不需要读取表块,因此不需要遭受了我上面描述的问题(即,一个表一个一个地读取每个表块)。

不是COUNT()AVG()“更快”。仅仅是在您的测试中,COUNT可以仅使用索引来计算,而AVG需要表中的信息。

答案 1 :(得分:1)

位图索引不应在OTLP系统中使用。他们的维护成本太高了。

IHMO纯B * tree索引就足够了。 INDEX RANGE SCAN从根到最左边的叶子起伏值“ 332”遍历,然后从左到右遍历所有具有相同“ B”值的叶子。这就是你想要的。

如果要进一步加快速度,可以创建所谓的覆盖索引。将“ B”和“ A”列(按此顺序)放入索引中。然后,当匹配“ B”时,将避免在表中查找“ A”的值。如果表包含许多您不关心的列,这将特别有用。