一列上有多个索引

Ale*_*ian 5 sql database oracle hibernate

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

列:Id,FirstName,LastName

索引:1. PK(Id),2.UPPER(FirstName),3. LOWER(FirstName),4. Index(FirstName)

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

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

例如:

SELECT Id FROM User u WHERE u.FirstName LIKE'MIKE%'

甲骨文会打出正确的指数还是不会?

问题是通过Hibernate这会使查询变得非常缓慢(因此它使用预处理语句).

谢谢.

更新:只是澄清索引2和3是功能索引.

Mat*_*Mat 7

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

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

select id from user u where upper(u.firstname) like 'MIKE%'
Run Code Online (Sandbox Code Playgroud)

编辑:看看这篇文章,有一些有趣的信息如何在Oracle 10+中包含NULL的列上使用基于函数的索引?

  • 同意删除2/3中的一个,但4对于区分大小写的匹配可能仍然有用,尽管你可以将其加倍,其中`upper(名字)如'MiKe%'和名字LIKE'MiKe%'`首先减少比赛 (3认同)
  • 你说的没错.区分大小写的搜索索引4可能很好.你对id列也非常正确.如果您只是在ID和名称之后可以产生巨大的差异,则无需访问数据块. (2认同)

Jus*_*ave 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桶直方图,它也不会有很多关于选择性事物的信息WHERE firstname LIKE 'Smit%'.它可能大致知道选择性'Sm%'是如何基于列直方图的,但是它相当盲目地猜测接下来两个字符的选择性.因此,在大多数查询有效工作的情况下最终会出现这种情况并不罕见,但优化程序确信它WHERE firstname LIKE 'Cave%'没有足够的选择性来使用索引.

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


Ric*_*iwi 6

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

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