2

我在一个部署在网络上的应用程序上工作。该应用程序的一部分是搜索功能,其中结果显示在排序列表中。该应用程序针对使用不同语言环境(= 排序规则)的多个国家/地区的用户。我需要为所有用户找到正确排序的解决方案。

我目前在我的 SQL 查询中使用 ORDER BY 进行排序,因此排序是根据为数据库设置的语言环境(或 LC_LOCATE)完成的。对于那些区域设置与数据库设置不同的用户,这些规则是不正确的。

此外,为了使问题进一步复杂化,我在应用程序中使用了分页,所以当我查询数据库时,我会根据我需要的页面询问第 1 - 15、16 - 30 行等。但是,由于排序错误,每个页面都包含排序错误的条目。在最坏的情况下,给定页面的整个结果集可能会乱序,具体取决于当前用户的区域设置/排序规则。

如果我要对(服务器端)代码进行排序,我需要从数据库中检索所有行然后排序。考虑到数据量,这会导致巨大的性能损失。因此,我想避免这种情况。

有没有人有策略(甚至技术解决方案)来解决这个问题,这将导致正确排序的列表而不必承受加载所有数据的性能损失?

技术细节:数据库是 PostgreSQL 8.3,应用程序是一个 EJB3 应用程序,使用 EJB QL 进行数据查询,在 JBoss 4.5 上运行。

4

5 回答 5

2

你愿意用 C 开发一个小的 Postgres 自定义功能模块吗?(对于有经验的 C 编码人员来说可能只有几天。)

strxfrm()是根据当前 LC_COLLATE 设置(或多或少当前语言)将依赖于语言的文本字符串转换为转换字符串的函数,如果按二进制字节序列排序(例如strcmp()),则该字符串会导致该语言中的正确排序顺序。

如果你为 Postgres 实现这个,假设它需要一个字符串和一个排序规则,那么你将能够通过 strxfrm(textfield, collat​​ion_order) 排序。我认为您甚至可以使用该函数在您的文本列上创建多个功能索引(例如每种语言一个)来存储 strxfrm() 的结果,以便优化器使用该索引。

或者,您可以与 Postgres 开发人员一起在主流 Postgres 中实现这一点。以下是有关此问题的 wiki 页面:Collat​​ionICU(据我所知,Java 也使用它)。


或者,如果数据仅通过 Java 输入,作为一种不太复杂的解决方案,您可以在将数据添加到数据库时用 Java 计算这些 strxfrm() 值(Java 可能对此概念有不同的名称),然后让 Postgres这些预先计算的值的索引和顺序。

于 2010-01-21T00:07:25.527 回答
0

此模块在 Postgres 8.4.3 中已损坏。我修复了它 - 您可以从http://www.itreport.eu/__cw_files/.01/.17/.ee7844ba6716aa36b19abbd582a31701/nls_string.c下载固定版本,您必须手动编译和安装它(如在相关的 README 和 INSTALL 来自原始模块),但无论如何排序工作不正确。我在 FreeBSD 8.0 上试过,LC_COLLATE 是 cs_CZ.UTF-8

于 2010-05-04T21:54:34.580 回答
0

我不知道有什么方法可以切换数据库order by顺序。因此,必须考虑其他解决方案。

如果结果的数量真的很大(数十万?),我没有解决方案,除了只显示结果的数量,并要求用户提出更精确的请求。否则,服务器端可以这样做,具体取决于确切的条件......

特别是,使用缓存可以极大地改善事情。对数据库的第一个请求(无限制)不会比结果数量有限的查询慢多少。随后的请求会快得多。通常,分页和重新排序会产生多个请求,因此缓存可以正常工作(即使持续几分钟)。

我使用 EhCache 作为技术解决方案。排序和分页一起进行,排序然后分页。原始结果可以存储在缓存中。

为了减少性能损失,一些提示:

  • 您可以针对结果集大小运行一次查询,并在结果过多时警告用户(要求确认慢速查询,或添加一些选择字段)
  • 只请求您需要的列,放开所有其他列(通常某些数据不会立即显示所有结果,而是显示在例如鼠标移动时;可以根据需要懒惰地请求这些数据,因此减少所有请求的列结果)
  • 如果您有计算值,缓存数据库列和计算值之间的较小值
  • 如果您在多个结果中有重复的值,您可以分别请求该数据/列(因此您从数据库中检索一次,并且只缓存一次),在主请求中只检索一个键(通常和 id)。
于 2009-08-20T16:58:01.360 回答
0

您与 PostgreSQL 的关系如何?该文档没有希望:

某些语言环境类别的性质是它们的值必须在数据库集群的生命周期内固定。也就是说,一旦 initdb 运行,您就不能再更改它们了。LC_COLLATE并且LC_CTYPE是那些类别。它们会影响索引的排序顺序,因此它们必须保持固定,否则文本列上的索引将损坏。PostgreSQL 通过记录initdb 看到的LC_COLLATE和的值来强制执行此操作。LC_CTYPE服务器在启动时会自动采用这两个值。

(排序规则定义文本的排序方式。)

谷歌抛出了正在讨论的补丁

PostgreSQL 目前一次只支持一种排序规则,由初始化数据库集群时的 LC_COLLATE 变量固定。

我不确定我是否想在数据库之外管理它,但我有兴趣阅读有关如何完成它的信息。(任何想要对这些问题有很好的技术概述的人都应该查看在Oracle 全球化站点上对Oracle 数据库中的语言数据进行排序。)

于 2009-08-20T16:34:08.163 回答
0

你可能想查看这个包:http ://www.fi.muni.cz/~adelton/l10n/postgresql-nls-string/ 。它已经很久没有更新了,可能不再工作了,但如果你想构建一个可以为你做这件事的函数,它似乎是一个合理的起点。

于 2010-01-21T08:50:13.097 回答