【问题标题】:Postgres 9.5.2 sorting differently in development vs productionPostgres 9.5.2 在开发与生产中的排序不同
【发布时间】:2016-08-17 09:58:56
【问题描述】:

更新

在我使用 postgresql 的 rails 应用程序中,我编写了一个 Active Record 查询来查找一组志愿者记录,然后按first_namelast_nameemail 对它们进行排序。此外,first_namelast_name 可能是 null(两者都将是 null 或两者都不是 null)。 Active Record 生成的 sql 如下所示:

SELECT DISTINCT LOWER(COALESCE("volunteers"."first_name", "volunteers"."email")), LOWER(COALESCE("volunteers"."last_name", "volunteers"."email")), LOWER("volunteers"."email"), "volunteers".* 
FROM "volunteers" 
INNER JOIN "volunteer_list_connectors" ON "volunteer_list_connectors"."volunteer_id" = "volunteers"."id" 
INNER JOIN "volunteer_lists" ON "volunteer_lists"."id" = "volunteer_list_connectors"."volunteer_list_id" 
WHERE ((volunteer_lists.organizer_id = 1 AND organizer_type = 'Organization') OR (volunteer_lists.organizer_id IN (1) AND organizer_type = 'Collaborative'))  
ORDER BY 
  LOWER(COALESCE("volunteers"."first_name", "volunteers"."email")) ASC, 
  LOWER(COALESCE("volunteers"."last_name", "volunteers"."email")) ASC, 
  LOWER("volunteers"."email") ASC

使用 Postgres 的 psql 工具,我将该 sql 复制并粘贴到我的开发机器和服务器上的 Postgres 中。在我的开发机器 (Mac) 上,该 sql 对以下列表进行了排序:

  1. 志愿者 [first_name:'Alex',last_name:'Diego',电子邮件: 'a.diego@person.com']
  2. 志愿者 [名字:null,姓氏:null,电子邮件: 'cxxr@person.com']
  3. 志愿者 [first_name:'Josh',last_name:'Broger',电子邮件: 'broger@person.com']
  4. 志愿者 [first_name:'Josh',last_name:'Broger',电子邮件: 'jcool@person.com']
  5. 志愿者 [名字:'Josh',姓氏:'Kenton',电子邮件: 'aj@person.com']

在我的生产环境 (Ubuntu) 中,Postgres 通过对列表进行排序来响应相同的代码:

  1. 志愿者 [名字:null,姓氏:null,电子邮件: 'cxxr@person.com']
  2. 志愿者 [first_name:'Alex',last_name:'Diego',电子邮件: 'a.diego@person.com']
  3. 志愿者 [first_name:'Josh',last_name:'Broger',电子邮件: 'broger@person.com']
  4. 志愿者 [first_name:'Josh',last_name:'Broger',电子邮件: 'jcool@person.com']
  5. 志愿者 [名字:'Josh',姓氏:'Kenton',电子邮件: 'aj@person.com']

区别在于只有一个电子邮件地址的志愿者总是排在其他志愿者之前。生产环境和开发环境都运行 PostgreSQL 9.5.2。两者都运行 Rails 4.2.6。

我一直无法弄清楚为什么我的应用程序在开发和生产中表现不同。

有人有什么想法吗?非常感谢任何需要进一步探索的帮助/领域!

更新 2

根据评论中的要求,这是我的开发机器和生产机器的 psql 输出。我稍微更改了查询以使图片可读。在这个查询中,我添加了一个LIMIT 10,我只要求first_namelast_nameemail,而不是整个记录。你必须相信我的话,这两个数据库都包含只有email 地址的volunteers 记录,以及first_namelast_nameemail 的记录。如果我的生产数据库按预期工作,它的输出将类似于第一张图片中的输出。

这个屏幕抓取显示了我的开发机器的psql 输出(好):

这个屏幕抓取显示了我的生产机器的psql 输出(坏)。因为这是输出中的真实用户数据,所以我模糊了电子邮件地址。但重要的一点是带有first_name = nulllast_name = null 的记录总是排在第一位,即使电子邮件地址的第一个字母是“Z”:

我可能是错的,但我认为生产机器的输出应该在每一列中显示电子邮件地址,COALESCE() 是否正常运行

回答

感谢@ClémentPrévost(以及@muistooshort 向我提出了正确的问题!)我能够找到答案:我认为没有正确排序的生产记录实际上在first_name 和@ 中有空白字符串987654354@ 而不是 null 值(并且 COALESCE() 只过滤掉 null 值,而不是空白字符串)。我用NULLIF("volunteers"."first_name", \'\') 更新了我的代码,一切都开始正确排序了!

SELECT DISTINCT LOWER(COALESCE(NULLIF("volunteers"."first_name", ''), "volunteers"."email")), LOWER(COALESCE(NULLIF("volunteers"."last_name", ''), "volunteers"."email")), LOWER("volunteers"."email"), "volunteers".* 
FROM "volunteers" 
INNER JOIN "volunteer_list_connectors" ON "volunteer_list_connectors"."volunteer_id" = "volunteers"."id" 
INNER JOIN "volunteer_lists" ON "volunteer_lists"."id" = "volunteer_list_connectors"."volunteer_list_id" 
WHERE ((volunteer_lists.organizer_id = 1 AND organizer_type = 'Organization') OR (volunteer_lists.organizer_id IN (1) AND organizer_type = 'Collaborative'))  
ORDER BY 
  LOWER(COALESCE(NULLIF("volunteers"."first_name", ''), "volunteers"."email")) ASC, 
  LOWER(COALESCE(NULLIF("volunteers"."last_name", ''), "volunteers"."email")) ASC, 
  LOWER("volunteers"."email") ASC

【问题讨论】:

  • 所以你的 ORDER BY 是LOWER(COALESCE("volunteers"."first_name", "volunteers"."email")) ASC, LOWER(COALESCE("volunteers"."last_name", "volunteers"."email")) ASC, LOWER("volunteers"."email") ASC,对吧?
  • 您的开发和生产数据库服务器是否使用相同的排序规则/语言环境?
  • PostgreSQL 将使用来自底层操作系统的一些整理信息,但不应将'c' 排序在'a' 之前。你确定没有空格或 Unicode 奇怪吗?生产中没有自定义排序规则?您能否向我们展示您在生产中查询的原始 psql 输出?
  • 这些真的是空字符串还是空字符串?您可以使用\pset null ¤ 来区分两者。
  • 到目前为止,我和@ClémentPrévost 在一起。 COALESCE 被破坏的可能性很小,first_name 更可能不是您认为的那样。

标签: postgresql sorting


【解决方案1】:

这些真的是空字符串还是空字符串?

您可以使用\pset null ¤来区分两者。

PS:问题cmets中的精彩讨论!

【讨论】:

    猜你喜欢
    • 2017-04-12
    • 2012-12-27
    • 1970-01-01
    • 1970-01-01
    • 2014-02-05
    • 1970-01-01
    • 2011-10-16
    • 2020-07-29
    • 2011-10-01
    相关资源
    最近更新 更多