【问题标题】:SQL query. Difference between exists and joinSQL 查询。存在和加入之间的区别
【发布时间】:2016-04-25 03:26:55
【问题描述】:

我有 4 张桌子:

create table Product(pCode integer primary key, pName varchar(20), Color varchar(10);
create table Cli(cCode integer primary key, cName varchar(20), city varchar(20));
create table Sale(pOut integer references Product(tCode), cOut integer references Client(cCode), countOut integer, dtOut date, primary key (pOut, kOut);
create table Buy (pIn integer references Product(pCode), cIn integer references Client(cCode), countIn integer, dtIn date, primary key (pIn, kIn);

我需要显示客户的姓名不是来自喀山,而是那些在 2015 年上半年购买一些商品,然后在 2015 年下半年销售相同商品的客户。

我通过使用视图解决了这个问题。

create view vA as select cCode from Cli where Cli.City <> 'Kazan';
create view vB(cCode, pCode) as select cOut, pOut from Sale where '01.01.2015'<=dtOut AND dtOut<'01.07.2015';
create view vC(cCode, tCode) as select cIn, tIn where '01.07.2015<=dtIn AND dtIn < '01.01.2016';
create view vD as select * from vB inner join vC on vB.cKod=vC.cKod AND vc.pCode=vB.pCode;
create view vE as select * from vD  right outer join on vA on vA.cCode=vD.cCode;
create view vF as select distinct c.Knam from Cli as c inner join vE on vE.cCode=c.cCode;

如果我要使用 join exists / not exists 会有所不同吗?

例如对于 vD - 存在而不是内部连接:

create view vD as select * from vB where exists(select * from vC where B.cCode=vC.cCode AND vc.pCode=vB.pCode);

对于 vE - 不存在而不是右外连接:

create view vE as select * from vA where not exists(select * from vD where vA.cCode=vD.cCode);

【问题讨论】:

  • 当您可以轻松地在单个查询中执行此操作时,为什么还要创建一堆视图?您的代码很难遵循,因为列名会切换,这使得提供更具体的建议变得更加困难。
  • 它们在逻辑上是不同的。 SELECT * FROM a WHERE EXISTS (SELECT anything from any table) 最多可以产生 card(a) 行,而SELECT * FROM a JOIN b ON (some condition possibly involving a and b) 最多可以产生 card(a) * card(b) 记录,可能比 card(a) 大。

标签: sql postgresql select join exists


【解决方案1】:

这是最好使用EXPLAIN回答的问题之一

我的猜测是,您会发现优化器在 INNER JOINWHERE EXISTS 之间选择了相同的方法(相反,Right Outer Join/Is NullNot Exists 在这种情况下大致相同,并且Postgres 有一个很好的优化器。

Here's a good example 的某人正在为您的 vE 查询进行完全相同的测试,他的结果是 Postgres 为这两种方法都选择了 Hash Anti Join

最后,如果您不确定哪条路线是最佳路线,只需将两者都写下来,看看哪条路线效果最好。查询运行后检查统计信息并查看Explain

【讨论】:

    【解决方案2】:

    我认为存在是一个更好的解决方案,因为常识告诉我它应该更快。如果您说“存在”,则意味着查询将在找到匹配项时停止,但是当您说“不存在”时,它需要遍历所有元素以确保它不存在。

    另外我想鼓励您使用更好的命名,因为查询现在很难阅读。

    【讨论】:

      猜你喜欢
      • 2015-08-17
      • 2011-06-11
      • 1970-01-01
      • 1970-01-01
      • 2017-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多