PostgreSQL:如果一个表被多次引用,则加入

时间:2018-10-04 13:43:09

标签: sql postgresql performance join subquery

如果多个表中的另一个表引用了一个表,那么从两个表中获取数据的最快方法是什么?

考虑一个带有公司名称的表和一个带有合同的表。每个合同在每个组合中可以具有clientintermediarycontractor。每个值可能是null,同一公司在每个合同行中可能是一,二或三倍。

表定义为:

CREATE TABLE company (id integer,name text);

CREATE TABLE contract (id integer, client integer, intermediary integer, contractor integer);

我用下面的测试da创建了一个SQL提琴: https://www.db-fiddle.com/f/irCodeZjeEPWvhmRwMcHqT/0

测试数据:

INSERT INTO company (id,name) VAlUES (1,'Company 1');
INSERT INTO company (id,name) VAlUES (2,'Company 2');
INSERT INTO company (id,name) VAlUES (3,'Company 3');
INSERT INTO company (id,name) VAlUES (4,'Company 4');
INSERT INTO company (id,name) VAlUES (5,'Company 5');
INSERT INTO contract (id,client,intermediary,contractor) VAlUES (1,NULL,NULL,NULL);
INSERT INTO contract (id,client,intermediary,contractor) VAlUES (2,NULL,2,3);
INSERT INTO contract (id,client,intermediary,contractor) VAlUES (3,1,NULL,NULL);
INSERT INTO contract (id,client,intermediary,contractor) VAlUES (4,NULL,2,NULL);
INSERT INTO contract (id,client,intermediary,contractor) VAlUES (5,1,2,3);
INSERT INTO contract (id,client,intermediary,contractor) VAlUES (6,4,NULL,5);
INSERT INTO contract (id,client,intermediary,contractor) VAlUES (7,1,NULL,1);
INSERT INTO contract (id,client,intermediary,contractor) VAlUES (7,3,3,3);

现在,使用PostgreSQL 9.6,需要一个查询,该查询返回合同ID以及所涉及的每个公司的名称。子查询非常简单:

SELECT
id, 
(SELECT name FROM company WHERE id = client) AS "clientName",
(SELECT name FROM company WHERE id = intermediary) AS "intermediaryName",
(SELECT name FROM company WHERE id = contractor) AS "contractorName"
FROM contract;

但是,在现实世界中,由于查询复杂得多,我们在这里遇到了性能问题。现在的问题是:是否有改进的方法? JOIN会比子查询快吗?如果是,那怎么办?

当然,您可以做类似

的操作

SELECT * FROM contract LEFT JOIN company ON company.id = ANY(ARRAY[client,contractor,intermediary]);

但是在这种情况下,丢失了哪家公司在合同中扮演的角色的信息。

(编辑:在现实世界中,有索引,外键约束和内容。为了简洁起见,我将所有内容都放在此处。)

2 个答案:

答案 0 :(得分:1)

您的方法很好,尽管您应该使用表别名:

final location = new MyTestLocation();
debugPrint( location.toString() );

return new MaterialApp(
  title: 'Welcome',
  home: new Scaffold(
    appBar: new AppBar(
      title: new Text('appBarTitle'),
    ),
      body: new Center(
        child: new Text( location.myTestString ),
      )
  ),
);

SELECT id, (SELECT c.name FROM company c WHERE c.id = co.client) AS "clientName", (SELECT c.name FROM company c WHERE c.id = co.intermediary) AS "intermediaryName", (SELECT c.name FROM company c WHERE c.id = co.contractor) AS "contractorName" FROM contract co; 应该是id中的主键-或在其上建立索引。

您也可以使用company来表达这一点:

left join

两种方法的性能应该非常相似。

答案 1 :(得分:0)

戈登的解决方案对我来说看起来不错(尤其是第二种解决方案,带有外部联接)。

您是否在表Contract中的Client,Intermediary和Contractor列上添加了外键和索引?