我正在使用PostgreSQL数据库,并且有4个表可以使用:注册表,发票,发票位置,user_involved
表注册表列:
id
reg_name
表格发票:
id
reg_id(FK to registry, can be many invoices in one registry)
invoice_name
表格发票位置:
id
invoice_id(FK to invoice, can be many positions in invoice)
position_name
表user_involved:
id
Inv_position_id(FK to invoice_position, it's a one to one relationship)
user_name
我需要创建一个SELECT查询,如果在 registry 表中出现了多次 user_involved (仅与user_involved与FK的invoice_position相关,则查找) ->发票->注册)。没什么要注意的是,这些表每个表都包含超过+/- 1.000.000行(EXCEPT注册表表),我目前不能在注册表和user_involved之间添加直接关系。问题是如何编写最佳的SELECT,或者即使在这种状态下也有可能,导致嵌套多个SELECT将永远花费。
编辑: 到目前为止,这是我尝试过的:
SELECT rg.id, COUNT(ui.id) FROM registry rg
LEFT JOIN invoice inv ON inv.reg_id = rg.id
LEFT JOIN invoice_position ip ON ip.invoice_id = inv.id
LEFT JOIN user_involved ui ON ui.inv_position_id = ip.id
WHERE ip.id = $id GROUP BY rg.id,ui.id HAVING COUNT (ui.id) > 1;
此查询将在 while 循环内,其中变量“ id”具有不同的发票位置ID。
答案 0 :(得分:0)
查询的关键方面之一是存在过滤条件。如果没有它,除了读取整个表,别无选择。当然,您不想这样做。
始终值得一提的替代方法是创建/使用/维护实例化视图。但这是我不在此讨论的主题,因为它需要做很多工作。我想,我认为这是不得已的选择。
无论如何,您的查询确实有一个过滤条件,尽管只有一个,这是一个相等条件(这很棒)。
在以下情况下,PostgreSQL可以充分利用此过滤器:
ip.id = $i
选择表行的5%或更少。理想情况下,我会将此限制设置为“小于0.5%”以使其真正快速。 该列上有一个用于过滤的索引。也就是说,该表的索引以列id
开头。也许只有该列的索引。例如:
create index ix1 on invoice_position (id);
如果您确认满足这些条件,请发布查询的执行计划。您可以通过在查询中添加EXPLAIN
子句来实现。它实际上不会执行查询,而只会显示您需要在问题中发布的计划。我可以阅读,并给我我的评估。
顺便问一下,您的过滤条件的选择性是什么?
答案 1 :(得分:0)
我将从做起:
EXPLAIN
SELECT rg.id, COUNT(ui.id)
FROM invoice_position ip, invoice inv, registry rg, user_involved ui
WHERE ip.id = $id
AND ip.invoice_id = inv.id
AND inv.reg_id = rg.id
AND ui.inv_position_id = ip.id
GROUP BY rg.id
HAVING COUNT(ui.id) > 1;
,然后看看您得到了什么。之所以不使用LEFT OUTER JOIN
,是因为它们限制了优化器可以选择的计划(或者至少是我上次检查时选择的计划),并且此查询似乎不需要它们。 / p>
此外,您可以考虑一次获取几行invoice_position
,并在数据库外部进行匹配。这样,您可以稍微分散执行查询的成本,但代价是调用代码的复杂性更高。
例如,类似
SELECT ip.id, rg.id, COUNT(ui.id)
FROM invoice_position ip, invoice inv, registry rg, user_involved ui
WHERE ip.id IN $id_list
AND ip.invoice_id = inv.id
AND inv.reg_id = rg.id
AND ui.inv_position_id = ip.id
GROUP BY ip.id, rg.id
HAVING COUNT(ui.id) > 1;