【问题标题】:SELECT by string prefix using an index使用索引按字符串前缀选择
【发布时间】:2013-03-13 15:06:28
【问题描述】:

您有一个字符串类型的列foo,该列上有一个索引。您想从表WHERESELECT foo 列具有前缀'pre'。显然,索引在这里应该可以提供帮助。

这是最明显的前缀搜索方式:

SELECT * FROM tab WHERE foo LIKE 'pre%';

不幸的是,这没有得到优化以使用索引(至少在 Oracle 或 Postgres 中)。

然而,以下确实有效:

SELECT * FROM tab WHERE 'pre' <= foo AND foo < 'prf';

但是有没有更好的方法来实现这一点,或者有没有让上面的更优雅的方法?特别是:

  • 我需要一个从'pre''prf' 的函数,但这必须适用于任何底层排序规则。此外,它比上面更复杂,因为如果搜索例如'prz' 那么上限必须是 'psa',以此类推。
  • 我能否将其抽象为一个存储的函数/过程并仍然命中索引?所以我可以写... WHERE prefix('pre', foo);之类的东西?

感谢所有 DBMS 的答案。

【问题讨论】:

  • 什么?不幸的是,这个'这确实得到了优化以使用索引'?有那么糟糕吗?当然,如果可能,“开始于”搜索会使用索引。感谢上帝,它确实如此。 ....我误会你了吗?
  • 大声笑,对不起,我不小心“不”这个词!已编辑
  • 哦,你的意思是在 SQL 中有一个“开始于”的结构吗?我找不到任何相关信息。
  • 是的,有Where Foo like 'bar%'会启用索引。
  • LIKE 'pre%' 不能在那些 DBMS 中使用索引,这很奇怪。至少在 SQL Server 中它是 sargable。

标签: sql arrays select indexing prefix


【解决方案1】:

数据库在这里非常重要。碰巧 SQL Server 对like 进行了这种优化。

一种方法是这样做:

where foo >= 'pre' and foo <= 'pre+'~'

'~' 具有可打印字符的最大 7 位 ASCII 值,因此它基本上比其他任何东西都大。但是,如果您使用宽字符或非标准字符集,这可能会成为问题。

您不能将其抽象为函数,因为函数的使用通常会排除索引的使用。如果您总是查看前三个字符,那么在 Oracle 中您可以为这三个字符创建索引(称为“基于函数的索引”)。

【讨论】:

  • 我认为foo &lt;= 'pre~' 不起作用,因为它会删除像'pre~fix' 这样的值。如果使用&lt;= 比较,则该值必须是pre~~~~~~~~~...,一直持续下去。函数的使用:我认为你是对的。也许 SQL 中的宏会是一件好事,但那是天上掉馅饼。
【解决方案2】:

怎么样

select * from tab where foo between 'pre' and 'prf' and foo != 'prf'

这会以同样的方式启用索引。 RDBMS 必须非常愚蠢才能使用索引。

【讨论】:

  • 您使用包含结束范围,然后必须指定另一个条件以使结束独占?为什么不foo &gt;= 'pre' AND foo &lt; 'prf'
  • 好问题。我没有尝试过,但从我的直觉看来,between 似乎更好。嗯……我是不是太相信我应该更多地去证明?
  • x BETWEEN l AND h 不只是 l &lt;= x AND x &lt;= h 的糖吗?
  • BETWEEN 再好不过了。正如@eegg 所说,它只是将语法糖扩展为两个 IN 扩展为 OR 表达式一样。你不会说'pre' &lt;= foo AND ' foo &lt;= 'pre' AND foo &lt;&gt; 'pre',对吗?所以使用BETWEEN 是“错误的”。也许将来更多的测试/证明比“本能”更好。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
相关资源
最近更新 更多