F.6. citext — 大小写不敏感的字符串类型 #
citext模块提供一种大小写不敏感的字符串类型
citext。本质上,它在比较值时会在内部调用
lower。除此之外,它的行为几乎与
text完全相同。
F.6.1. 原理
在PostgreSQL中进行大小写不敏感匹配的标准方法,一直是在比较值时使用lower函数,例如:
SELECT * FROM tab WHERE lower(col) = LOWER(?);
这种做法效果尚可,但有几个缺点:
它会让 SQL 语句变得冗长,而且你必须时刻记得同时对列和查询值调用
lower。除非你创建一个使用
lower的函数索引,否则它不会使用索引。如果把列声明为
UNIQUE或PRIMARY KEY,隐式生成的索引仍然是大小写敏感的。因此,它既无法用于大小写不敏感搜索,也不能以大小写不敏感的方式强制唯一性。
citext 数据类型让你可以免去在 SQL 查询中调用
lower,并且允许主键不区分大小写。与
text 一样,citext 也与区域设置相关,这意味着大写字符和小写字符如何比较取决于 LC_CTYPE 区域设置的规则。同样,这种行为与在查询中使用 lower 完全一致。但由于这是由数据类型透明地完成的,因此你不必在查询中额外记住任何特殊处理。
F.6.2. 如何使用
下面是一个简单的使用示例:
CREATE TABLE users (
nick CITEXT PRIMARY KEY,
pass TEXT NOT NULL
);
INSERT INTO users VALUES ( 'larry', md5(random()::text) );
INSERT INTO users VALUES ( 'Tom', md5(random()::text) );
INSERT INTO users VALUES ( 'Damian', md5(random()::text) );
INSERT INTO users VALUES ( 'NEAL', md5(random()::text) );
INSERT INTO users VALUES ( 'Bjørn', md5(random()::text) );
SELECT * FROM users WHERE nick = 'Larry';这个SELECT语句仍会返回一个元组,尽管nick列中存的是larry,而查询条件写的是Larry。
F.6.3. 字符串比较行为
为了尽可能贴近大小写不敏感排序规则的行为,许多比较操作符和函数都提供了 citext 专用版本。例如,当应用于
citext 时,正则表达式操作符 ~ 和
~* 表现相同:它们都会以大小写不敏感的方式比较。!~ 和 !~* 也是如此,LIKE 操作符 ~~ 和 ~~*、以及 !~~ 和 !~~* 也一样。如果你希望进行大小写敏感匹配,可以先转换为 text 再比较。
同样地,如果这些函数的参数是citext,它们也会以大小写不敏感方式进行匹配:
regexp_replace()regexp_split_to_array()regexp_split_to_table()replace()split_part()strpos()translate()
对于正则表达式函数,如果你想按大小写敏感方式匹配,可以指定
“c”标志来强制大小写敏感匹配。否则,若要获得大小写敏感行为,就必须在调用这些函数之前先把值转换为text。
F.6.4. 限制
citext的大小写折叠行为依赖于数据库的LC_CTYPE设置,因此它如何比较值是在运行 initdb 创建群集时确定的。按照 Unicode 标准中的定义,它并不是真正意义上的大小写不敏感。实际上,这意味着只要你对当前排序规则满意,通常也会对citext的比较结果满意。但是,如果数据库中存有多种语言的数据,而排序规则只适用于其中某一种语言,那么其他语言的用户可能会发现查询结果并不符合预期。citext不如text高效,因为操作符函数和 B-树比较函数必须复制数据,并将数据转换为小写后才能进行比较。不过,在需要大小写不敏感匹配时,它仍然比使用lower略高效一些。如果你在某些场景下需要大小写敏感比较,而在另一些场景下又需要大小写不敏感比较,那么
citext并不会帮上太多忙。标准做法是使用text类型,并在需要大小写不敏感比较时手工调用lower;如果这类比较只是偶尔出现,这种做法是完全可行的。如果你大多数时候都需要大小写不敏感行为,而只是在少数场景下需要大小写敏感比较,那么可以考虑把数据存储为citext,并在需要大小写敏感比较时显式地把列转换为text。无论哪种情况,如果你希望这两类搜索都足够快,就都需要建立两个索引。包含
citext操作符的模式必须位于当前search_path中(通常是public);如果不在,执行的将是普通的、大小写敏感的text比较。