SQL 查询。 exists 和 join 的区别
SQL query. Difference between exists and join
我有 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);
我认为 exists 是更好的解决方案,因为常识告诉我它应该更快。如果您说 "exists" ,这意味着查询将在找到匹配项时停止,但是当您说 "not exist" 时,它需要遍历所有元素以确保它不存在。
我还想鼓励您使用更好的命名方式,因为查询现在很难阅读。
这是使用 EXPLAIN
最好回答的问题之一
我猜你会发现优化器在 INNER JOIN
和 WHERE EXISTS
之间选择相同的方法(相反 Right Outer Join
/Is Null
与 Not Exists
因为在这种情况下它们大致相同,而且 Postgres 有一个很好的优化器。
Here's a good example 的人正在为您的 vE
查询做完全相同的测试,他的结果是 Postgres 为这两种方法选择了 Hash Anti Join
。
最后,如果您不确定哪条路线是最佳路线,请将两者都写下来,看看哪种路线效果最好。查询运行后检查统计信息并查看 Explain
.
我有 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);
我认为 exists 是更好的解决方案,因为常识告诉我它应该更快。如果您说 "exists" ,这意味着查询将在找到匹配项时停止,但是当您说 "not exist" 时,它需要遍历所有元素以确保它不存在。
我还想鼓励您使用更好的命名方式,因为查询现在很难阅读。
这是使用 EXPLAIN
我猜你会发现优化器在 INNER JOIN
和 WHERE EXISTS
之间选择相同的方法(相反 Right Outer Join
/Is Null
与 Not Exists
因为在这种情况下它们大致相同,而且 Postgres 有一个很好的优化器。
Here's a good example 的人正在为您的 vE
查询做完全相同的测试,他的结果是 Postgres 为这两种方法选择了 Hash Anti Join
。
最后,如果您不确定哪条路线是最佳路线,请将两者都写下来,看看哪种路线效果最好。查询运行后检查统计信息并查看 Explain
.