一列上有多个索引

时间:2011-03-08 21:23:20

标签: sql database oracle hibernate

使用Oracle,有一个名为User的表。

列:Id,FirstName,LastName

索引:1。PK(Id),2。UPPER(名字),3。LOWER(名字),4。Index(名字)

正如您所看到的,索引2,3,4是同一列上的索引 - FirstName。

我知道这会产生开销,但我的问题是选择数据库如何反应/优化?

例如:

  

SELECT Id FROM User u WHERE   u.FirstName喜欢'MIKE%'

Oracle会遇到正确的指数还是不会?

问题在于,通过Hibernate,查询速度非常慢(因此它使用预处理语句)。

感谢。

UPDATE :只是为了澄清索引2和3是功能索引。

3 个答案:

答案 0 :(得分:7)

在同一个字段上同时使用基于函数的上部和下部索引有点奇怪。我认为优化器不会在您的查询中使用它。

你应该选择其中一个(也可能会删除最后一个),并且只能在上面(或下面)查询 - 例如:

select id from user u where upper(u.firstname) like 'MIKE%'

编辑:也请看这篇文章,有一些有趣的信息How to use a function-based index on a column that contains NULLs in Oracle 10+?

答案 1 :(得分:7)

除了Mat的观点之外,索引2或3应该是多余的,因为你应该选择一种方法来进行不区分大小写的搜索,而理查德指出它将取决于索引的选择性,请注意还有其他使用LIKE子句时的问题。

假设您正在使用绑定变量(听起来您基于使用预准备语句),优化器必须猜测实际绑定值的选择性。像'S%'那样短的东西将非常非选择性,导致优化器通常更喜欢表扫描。另一方面,像'Smithfield-Manning%'这样的较长字符串很可能是非常有选择性的,可能会使用索引4. Oracle如何处理这种可变性将取决于版本。

在Oracle 10中,Oracle引入了绑定变量peeking。这意味着Oracle在重新启动后第一次解析查询(或者在查询计划从共享池中老化之后),Oracle查看绑定值并根据该值确定要使用的计划。假设您的大多数查询都会从索引扫描中受益,因为用户通常会搜索相对选择性的值,如果重新启动后的第一个查询具有选择性条件,则这很好。但是如果你运气不好并且有人在重新启动后立即执行了WHERE firstname LIKE 'S%',那么你将无法使用表扫描查询计划,直到从共享池中删除了查询计划。

然而,从Oracle 11开始,优化器能够进行自适应游标共享。这意味着优化器将尝试确定WHERE firstname LIKE 'S%'应执行表扫描,WHERE firstname LIKE 'Smithfield-Manning%'应执行索引扫描,并将为共享池中的同一语句维护多个查询计划。这解决了我们在早期版本中使用绑定变量查看时遇到的大多数问题。

但即使在这里,优化器的选择性估计的准确性通常对于中等长度的字符串也是有问题的。通常会知道单字符串的选择性非常弱,而且20个字符的字符串具有高度选择性,但即使使用256个桶直方图,它也不会有大量有关{{1}之类的选择性信息的信息。 }} 真的是。它可能大致知道选择性'Sm%'是如何基于列直方图的,但是它相当盲目地猜测接下来两个字符的选择性。因此,最常见的情况是大多数查询都能有效运行但优化程序确信WHERE firstname LIKE 'Smit%'没有足够的选择性来使用索引。

假设这是一个常见查询,您可能需要考虑使用Oracle的计划稳定性功能来强制Oracle使用特定计划,而不管绑定变量的值如何。这可能意味着输入单个字符的用户必须等待比原本等待的更长的用户,因为索引扫描的效率远低于进行表扫描。但对于那些正在寻找简短却又名副其实的姓氏的其他用户而言,这可能是值得的。并且您可以执行诸如向查询添加ROWNUM限制器或向搜索框中需要最少字符数的前端添加逻辑以避免表扫描更有效的情况。

答案 2 :(得分:6)

它可能没有命中任何索引,因为您在SELECT子句中返回ID,索引不会覆盖它。

如果索引是非常有选择性的,并且Oracle决定使用它来查找“MIKE%”然后执行查找数据以获取ID列,那么它可能会使用4. Index(FirstName)。仅当搜索的列使用索引中定义的确切函数时,才会使用2和3。