我应该如何重构子查询

时间:2018-11-04 02:41:34

标签: sql sql-server

我知道将子查询写入查询的三种方式。

  • 普通子查询
  • 有子句
  • 临时表

当查询中有多个子查询时,尤其是嵌套子查询时,子查询会变得非常混乱。

With子句是我的偏爱,但是您只能在直接在WITH子句之后的select语句中使用WITH子句中的子查询(我相信)。

临时表很好,但是声明表需要很多开销。

除这些子查询之外,还有其他方法可以重构子查询吗? 还有我之间没有考虑过的折衷方案吗?

2 个答案:

答案 0 :(得分:1)

作为优先考虑事项和可读性而不是性能,with可能是最好的。

我不知道您使用的是哪个数据库,但是在Oracle中,with创建了一个temporary view/table accessible with the name on the LHS of the as,并且与子查询并没有真正的区别:可以像使用普通表一样使用该名称。

select * from (select * from a)的操作相同:唯一的问题是您不能重复使用该结果:

select * from (subquery1) q left join t1 on t1.id = q.id
union all
select * from (subquery1) q left join t2 on t2.id = q.id;

但这就是查询计划很重要的地方:subquery1在两种情况下都是相同的,并且该计划可能是使用临时表/视图的计划,从而降低了整体成本。

with最终是一种创建临时表/视图的方法,还可以迫使计划优化器以某种顺序(可能(不是)最佳)构建查询。

如果您知道结果将在以后重用,而不是在同一查询中使用(在这种情况下,with会执行相同的工作,给定使用的临时表),那么临时表将是很好的选择,甚至是事务处理(示例:保存搜索结果):

begin
  insert into tmp (...); 
  select * from tmp q left join t1 on t1.id = q.id;
  select * from tmp q left join t2 on t2.id = q.id;
end;

tmp表在同一事务中使用两次,但不在同一查询中使用:您的数据库不会两次重新计算结果,如果您所做的全部是selecttmp上没有突变。)

答案 1 :(得分:1)

您将忽略其他功能。

最明显的是视图。如果您有一个将要多次使用的复杂查询(尤其是可能在表之间实现业务规则的查询),则视图非常有用。如果性能是一个问题,那么您可以实现视图。

子查询的常见用法是在表中生成其他列-例如两列之间的差异。您可以将计算列用于这些计算,并使它们成为数据定义的一部分。

最后,您可以实现用户定义的功能。用户定义的表值函数与带有参数的视图非常相似。在某些情况下,这确实很有帮助。而且基本查询通常应该进行优化。

另一种用户定义函数是标量函数。这些通常会产生更多的开销,但有时会很有用。

所有这些说明,如果您整洁地构造查询,则子查询和CTE不会看起来“混乱”。您可能实际上发现您可以编写很长的查询,这对您和阅读它们的其他人都有意义。