在Microsoft SQL Server中,可以指定“不区分重音”排序规则(用于数据库、表或列),这意味着可以对
SELECT * FROM users WHERE name LIKE 'João'
查找名称为Joao
行。
我知道在PostgreSQL中使用unaccent_string contrib函数可以去除字符串中的重音,但我想知道PostgreSQL是否支持这些“不区分重音”的排序规则,以便上面的SELECT
可以工作。
在Microsoft SQL Server中,可以指定“不区分重音”排序规则(用于数据库、表或列),这意味着可以对
SELECT * FROM users WHERE name LIKE 'João'
查找名称为Joao
行。
我知道在PostgreSQL中使用unaccent_string contrib函数可以去除字符串中的重音,但我想知道PostgreSQL是否支持这些“不区分重音”的排序规则,以便上面的SELECT
可以工作。
3条答案
按热度按时间byqmnocz1#
更新Postgres 12或更高版本
Postgres 12增加了非确定性ICU排序规则,支持不区分大小写和重音的分组和排序。
只有在构建PostgreSQL时配置了ICU支持时,才能使用ICU语言环境。
如果是这样,这对您很有用:
fiddle
详细信息请阅读手册。这个blog post by Laurenz Albe可能有助于理解。
但是ICU排序也有缺点。手册:
[...]它们也有一些缺点。最重要的是,使用它们会导致性能下降。请特别注意,B树不能对使用不确定排序规则的索引使用重复数据删除。此外,某些操作(如模式匹配操作)不能使用不确定排序规则。因此,它们应仅在特别需要的情况下使用。
我的“遗留”解决方案可能仍然更优越:
适用于所有版本
使用unaccent module来实现这一点--这与您链接到的内容完全不同。
unaccent是一个文本搜索词典,它从词位中删除重音符号(发音符号)。
每个数据库安装一次,使用:
如果出现如下错误:
按照相关答案中的说明在数据库服务器上安装contrib包:
除此之外,它还提供了可以在示例中使用的函数
unaccent()
(其中似乎不需要LIKE
)。索引
IMMUTABLE
函数作为索引。如果函数可以为相同的输入返回不同的结果,则索引可能会自动中断。unaccent()
仅限STABLE
而非IMMUTABLE
不幸的是,
unaccent()
只是STABLE
,而不是IMMUTABLE
。根据pgsql-bugs上的这个线程,这是由于 * 三 * 个原因:1.这取决于字典的行为。
1.这本词典没有硬连线连接。
1.因此,它还取决于电流
search_path
,电流search_path
很容易改变。web上的Some tutorials指示只将函数volatile更改为
IMMUTABLE
。这种暴力方法在某些情况下可能会崩溃。其他人建议使用一个简单的
IMMUTABLE
Package 函数(就像我自己过去做的那样)。关于是否使用两个参数
IMMUTABLE
来显式声明所使用的字典,目前还存在争议。另一个替代方案是Github上提供的IMMUTABLE
unaccent()
function by Musicbrainz模块。我自己还没有测试过。我想我已经想出了一个***更好的主意***:目前最佳
这种方法比其他浮动解决方案更高效,也更安全。
创建一个
IMMUTABLE
SQL Package 函数,该函数使用硬连接的模式限定函数和字典执行双参数表单。由于嵌套一个非不可变函数会禁用函数内联,因此将其基于C函数的副本,(fake)声明为
IMMUTABLE
。它的 * 唯一 * 用途是用于SQL函数 Package 。而不是用于它自己。由于没有办法在C函数的声明中硬连接字典,因此需要复杂性。(这需要破解C代码本身。)SQL Package 函数可以做到这一点,并允许函数内联 * 和 * 表达式索引。
然后道:
在Postgres 14或更高版本中,SQL标准函数的成本稍低,但是:
请参阅:
从Postgres 9.5或更早版本的两个函数中删除
PARALLEL SAFE
。public
是安装扩展的模式(默认值为public
)。显式类型声明(
regdictionary
)可以防御恶意用户使用函数的重载变体进行的假设攻击。STABLE
函数unaccent()
的 Package 函数。它禁用了function inlining。这个版本的执行速度比我之前使用的简单 Package 函数快十倍。这已经是第一个版本的两倍了,第一个版本将
SET search_path = public, pg_temp
添加到函数中--直到我发现字典也可以是模式限定的。如果您缺少创建C函数所需的权限,则返回到次佳实现:
IMMUTABLE
函数 Package 函数,用于封装模块提供的STABLE
unaccent()
函数:最后,表达式索引使查询 * 快速 *:
记住,在函数或字典发生任何变化后,重新创建索引,就像不会重新创建索引的主版本升级一样。最近的主版本都对
unaccent
模块进行了更新。调整查询以匹配索引(以便查询计划器使用它):
我们不需要运算符右边的表达式中的函数,也可以直接提供
'Joao'
这样的无重音字符串。使用**expression index**,更快的函数并不能转换为更快的查询。索引查找对预先计算的值进行操作,无论哪种方式都非常快。但是索引维护和查询不使用索引的好处。像bitmap index scans这样的访问方法可能必须 * 重新检查 * 堆(主关系)中的值,这涉及到执行底层函数。请参见:
Postgres 10.3 / 9.6.8等增强了客户端程序的安全性。在任何索引中使用时,您 * 需要 * 对函数和字典名称进行模式限定。请参见:
连字
在Postgres**9.5或更早版本中,**连字如''或'ß'必须手动扩展(如果需要),因为
unaccent()
总是替换 * 单个 * 字母:你会喜欢这个更新,以不强调在Postgres9.6:
扩展
contrib/unaccent
的标准unaccent.rules
文件以处理Unicode已知的所有音调符号,并正确扩展连字(托马斯Munro,Léonard Benedetti)大胆强调我的。现在我们得到:
模式匹配
对于具有任意模式的**
LIKE
或ILIKE
**,将其与PostgreSQL 9.1或更高版本中的模块pg_trgm
组合。创建三元组GIN(通常更可取)或GIST表达式索引。GIN的示例:可用于以下查询:
GIN和GIST索引的维护成本比普通B树更高:
对于左锚定模式有更简单的解决方案。更多关于模式匹配和性能的信息:
pg_trgm
还为“相似性”(%
)和“距离”(<->
)提供了有用的运算符。三元组索引还支持
~
等的简单正则表达式和ILIKE
的不区分大小写模式匹配:1sbrub3j2#
否,PostgreSQL不支持这种排序规则
PostgreSQL不支持这样的排序规则(不管是否区分重音),因为除非是二进制相等,否则任何比较都不会返回相等。这是因为在内部,它会给哈希索引之类的东西带来很多复杂性。因此,严格意义上的排序规则只影响排序而不影响相等。
解决方法
全文查找-搜寻不含重音字汇的字典。
对于FTS,可以使用
unaccent
定义自己的字典,然后可以使用函数索引对它进行索引,
您现在可以非常简单地查询它
另请参阅
自己不重音符。
unaccent
module也可单独使用,无需集成FTS,请查看Erwin's answerkwvwclae3#
我很确定PostgreSQL依赖于底层操作系统进行排序。它 * 确实 * 支持creating new collations和customizing collations。不过我不确定这对你来说会有多少工作。(可能会相当多。)