阿弟(陈爱生)测试发现,UTF-8下 locale 选用 C 和 zh_CN 性能差距非常大:
http://bbs.pgsqldb.com/client/post_show.php?zt_auto_bh=57394
以前修改过这个字符类型比较的部分,当时遇到的问题是,依赖于操作系统实现不同,字母排序可能会出现:
A a B b C c ... 而不是 A B C ... a b c ...
解决方法实现进行 ascii 字符比较,无法得出结果再进行编码转化比较。
此方法也同样可以解决性能问题,虽然有些特殊情形可能反而带来额外开销,相对而言,个人认为总体结果还是提升的。
字符串比较函数varstr_cmp 定义在 src/backend/utils/adt/varlena.c 中,我们挑几部分来看:
if (lc_collate_is_c(collid))
{
result = memcmp(arg1,arg2,Min(len1,len2));
if ((result == 0) && (len1 != len2))
result = (len1 < len2) ? -1 : 1;
}
collate == C 时,直接作内存比较。
下边的代码可以看到,在Windows下需要首先转换成 UTF-16,随后不管哪个系统都会调用系统函数 strcoll_l 或者 strcoll。
对于简体汉字,根据编码规则,所有汉字(包括全角字符)的 UTF-8 编码下每个字节都是大于127,也就是首位为1。对于一个以 ascii字符开始的字符串,我们很容易就能判断出他们之间的大小关系,根本不必去进行转换,除非缀前缀完全一样。在转换编码之前,如果编码是 PG_UTF8,我们逐个字符对比,如果ascii 码根据其大小就知道返回结果,不需要再继续;如果不是,那就不得不调用 strcoll 比较;所有 ascii码,认为他们都小于汉字。具体逻辑不写在这里了,大致思路如此。
这样的改动,我想一个应用系统,相当一部分的字符比较,可以不通过编码转换来完成,性能自然也就提高不少。