具有分页的区域设置敏感排序策略

时间:2009-08-20 09:48:43

标签: java postgresql sorting pagination locale

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

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

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

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

有没有人有策略(甚至是技术解决方案)来攻击这个问题,这会产生正确排序的列表,而不必考虑加载所有数据的性能?

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

5 个答案:

答案 0 :(得分:2)

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

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

如果你为Postgres实现这个,说它需要一个字符串和一个整理顺序,那么你就可以通过strxfrm(textfield,collat​​ion_order)来订购。我想你甚至可以在你的文本列上创建多个功能索引(比如每种语言一个),使用该函数存储strxfrm()的结果,以便优化器使用索引。

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


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

答案 1 :(得分:0)

你对PostgreSQL的关系如何? documentation并不乐观:

  

某些区域设置类别的性质是它们的值必须在数据库群集的生命周期内得到修复。也就是说,一旦initdb运行,​​你就不能再改变它们了。 LC_COLLATELC_CTYPE是这些类别。它们会影响索引的排序顺序,因此必须保持它们不变,否则文本列上的索引将会损坏。 PostgreSQL通过记录initdb看到的LC_COLLATELC_CTYPE的值来强制执行此操作。服务器启动时自动采用这两个值。

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

Google引发了patch under discussion

  

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

我不确定我是否想在数据库之外管理这个,但我有兴趣阅读它是如何完成的。 (想要对问题进行良好技术概述的任何人都应该在Sorting Your Linguistic Data inside the Oracle Database上查看Oracle globalization site。)

答案 2 :(得分:0)

我不知道切换数据库order by顺序的任何方法。因此,必须考虑其他解决方案。

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

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

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

为了降低性能,一些提示:

  • 您可以针对结果集大小运行一次查询,并在结果太多时警告用户(要求确认慢查询或添加一些选择字段)
  • 仅请求您需要的列,放开所有其他列(通常一些数据不会立即显示所有结果,但会在鼠标移动时显示;此数据可以懒惰地请求,仅根据需要,因此减少所有结果所要求的列数)
  • 如果您有计算值,请在数据库列和计算值之间缓存较小的
  • 如果您在多个结果中有重复值,则可以单独请求数据/列(这样您只需从数据库中检索一次,并只缓存一次),只检索一个键(通常,和主要请求中的id。

答案 3 :(得分:0)

您可能想要查看此打包:http://www.fi.muni.cz/~adelton/l10n/postgresql-nls-string/。它在很长一段时间内没有更新,可能不再起作用,但如果你想构建一个可以为你做这个的功能,它似乎是一个合理的起点。

答案 4 :(得分: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