【问题标题】:SQL to detect inconsistency between 1:M and M:M relationsSQL 检测 1:M 和 M:M 关系之间的不一致
【发布时间】:2014-05-31 20:28:54
【问题描述】:

我在一个由 PostgreSQL 数据库支持的 Django 应用程序中有四个表:

  • 客户
  • 销售订单
  • 用户组
  • CustomerToUserGroupMembership

从 SalesOrder 到 UserGroup 有一个标准外键,并且 Customer 和 UserGroup 之间存在 M:M 关系。所有表都有一个uuid 列作为PK。

最终,我尝试使用快速 SQL 查询来查找订单,该查询将在 Python 条件中表示为 order.userGroup not in order.customer.userGroups.all()

我尝试了类似的方法:

SELECT o.uuid 
FROM myapp_salesorder o JOIN myapp_customer c ON o.customer_id = c.uuid
WHERE o."userGroup_id" NOT IN (
    SELECT m."userGroup_id" FROM myapp_customertousergroupmembership m 
    WHERE m.customer_id = c.uuid
);

...但是子选择确实减慢了速度。

有没有更好的方法来制作它以使其更快?

【问题讨论】:

    标签: python sql django postgresql


    【解决方案1】:

    对此有不同的方法。对于你的情况,我会使用not exists:

    SELECT o.uuid 
    FROM myapp_salesorder o JOIN
         myapp_customer c
         ON o.customer_id = c.uuid
    WHERE NOT EXISTS (SELECT 1
                      FROM myapp_customertousergroupmembership m 
                      WHERE m.customer_id = c.uuid AND m.userGroup_id = o.userGroup_id
                     );
    

    为获得最佳性能,请在 myapp_customertousergroupmembership(customer_id, userGroup_id) 上创建复合索引。

    编辑:

    join 版本很简单:

    SELECT o.uuid 
    FROM myapp_salesorder o JOIN
         myapp_customer c
         ON o.customer_id = c.uuid LEFT JOIN
         myapp_customertousergroupmembership m
         ON m.customer_id = c.uuid AND m.userGroup_id = o.userGroup_id
    WHERE m.customer_id IS NULL;
    

    不过,我不知道性能会不会更好。

    【讨论】:

    • 谢谢戈登。我尝试在打开 postgres 计时的情况下运行此版本,但它在数据库的受限子集中运行得稍慢。我的版本耗时 796 毫秒,而你的版本耗时 821 毫秒。有没有办法用纯 JOIN 和没有子选择来做到这一点?
    • 对不起:@Gordon Linoffs 的计划不能慢,除非你作弊。
    • 我发现原始问题中的查询结果实际上是错误的(它返回的结果多于应有的结果,尽管我不确定为什么),因此通过这种方式衡量速度差异是无关紧要的戈登的回答很有帮助。
    猜你喜欢
    • 1970-01-01
    • 2022-01-04
    • 2014-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多