繁体   English   中英

编写包含太多联接的查询的最佳方法

[英]Best way to write a query with too many joins

我有一个数据库表(我们称之为project )和许多其他表,这些其他表中的大多数都有一个引用表project的外键( id_project )。

这个查询的目标是返回项目现在处于哪个阶段(一个项目一点一点地发展直到它结束)并且有超过20个项目可能经过的表,我对此的解决方案是使用太多加入并查看哪个表具有这样的 null 个值

SELECT
    p.id_project
    CASE
        WHEN po.id IS NOT NULL THEN 'payment completed'
        WHEN b.id IS NOT NULL THEN 'bill received'
        WHEN e.id IS NOT NULL THEN 'project engaged'
        --(and still many other cases)
       ELSE 'start of the project'
    END AS progress
FROM 
    project p
LEFT JOIN
    decision d ON d.id_project = p.id_project
LEFT JOIN 
    engagement e ON e.id_project = p.id_project
LEFT JOIN 
    bill b ON b.id_project = p.id_project
LEFT JOIN 
    payment_order po ON po.id_project = p.id_project
LEFT JOIN  
    --..... (many other tables)

此查询最多需要大约 9 秒来执行,并且使用得非常频繁(作为从其他查询调用的视图)。

是否有可能有另一个更好的解决方案,或者是这种或另一种方法?

现在谈谈另一种方法? 一个项目目前只能处于一个阶段; 正确的? 因此,您可以更改PROJECT表并添加一个新列 - PROJECT_PHASE - 其中将包含当前阶段。 该专栏将在项目进入另一个阶段后立即更新; 按照我的理解,它是在这 20 个表中的任何一个中创建新行的时候。

另一种选择是创建一个新表project_phase ,其中将包含id_project和“id_phase”组合(以及时间戳等)。

任何方法都意味着您可以快速获取当前项目阶段,而无需外部连接 20 个(大?)表,这需要时间。

我们不知道您的数据,但您的数据库设计显示了所有表的 1:n 关系,即一个项目的多个决策、一个项目的多个参与、多个账单等。现在让我们假设有三个决策,三个参与到目前为止,一个项目有四张账单。 您单独加入项目 ID 上的所有行。 这称为每个项目的笛卡尔积,创建所有组合(每一行与另一行)单独为这个项目产生 3 x 3 x 4 = 36 行。

我很惊讶你自己没有注意到这一点,因为你说你已经在使用查询并且没有发生聚合。 或者这就是您所说的“太多连接”?

不用交叉连接所有这些行,只需使用EXISTSIN查找表。

SELECT
  p.id_project,
  CASE
    WHEN p.id_project IN (SELECT po.id_project FROM payment_order po) THEN 'payment completed'
    WHEN p.id_project IN (SELECT b.id_project  FROM bill b)           THEN 'bill received'
    WHEN p.id_project IN (SELECT e.id_project  FROM engagement e)     THEN 'project engaged'
    -- (and still many other cases)
    ELSE 'start of the project'
  END AS progress
FROM project p;

一种更快的替代方法是按照 Littlefoot 的建议将状态存储在项目表中(理想情况下是状态表),然后在所有更新该状态的表上设置触发器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2025 STACKOOM.COM