【问题标题】:Is there some equivalent to subquery correlation when making a derived table?制作派生表时是否存在与子查询相关性等价的东西?
【发布时间】:2025-12-14 23:20:12
【问题描述】:

我需要在一个垂直表中展平 2 行(然后连接到第三个表)我通常通过为我需要的每个字段制作一个派生表来做到这一点。只有两个字段,我认为这并没有那么不合理。

但我知道我想要返回到派生表中的行是与我的第三个表连接的子集。 所以我试图找出最好的派生表,以便查询最有效地运行。

我认为派生表的 where 子句越严格,派生表越小,得到的响应就越好。

我真正想要的是将派生表的 where 子句与与第三个表的连接相关联,但是您不能在 sql 中这样做,这太糟糕了。不过我不是sql高手,可能有一些我不知道的技巧。

另一种选择是制作没有 where 子句的派生表,它最终会加入整个表两次(每个字段一次),当我对它们进行联接时,联接会过滤所有内容出去。

所以我真正要问的是,我想创建一个派生表的最佳方法是什么,我非常清楚我想要什么行,但 sql 不会让我得到它们。

一个例子:

table1
------

id  tag     value
--  -----   -----
1   first   john
1   last    smith
2   first   sally
2   last    smithers


table2
------

id     occupation
--     ----------
1      carpenter
2      homemaker


select table2.occupation, firsttable.first, lasttable.last from
table2, (select value as first from table1 where tag = 'first') firsttable,
(select value as last from table1 where tag = 'last') lasttable
where table2.id = firsttable.id and table2.id = lasttable.id

我要做的是创建 firsttable where 子句 where tag='first' and id = table2.id

【问题讨论】:

  • 你能提供一些可以提供良好视觉效果的示例表和结果吗?

标签: sql sybase derived-table


【解决方案1】:

DERIVED 表不会像您期望的那样存储中间结果。这些只是使代码更简单的一种方法。使用派生表并不意味着派生表表达式将首先执行,其输出将用于与其余表连接。在大多数情况下,优化器会自动取消派生表。

但是,在某些情况下,优化器可能希望存储子查询的结果,从而实现实体化而不是扁平化。这通常发生在您有某种聚合函数或类似的情况时。但在您的情况下,查询也是简单,因此优化器将展平查询

此外,存储派生表表达式不会使您的查询变快,反而会使查询变得更糟。您真正的问题是过多的规范化。修复该查询将只是两个表的连接。

为什么要进行这种规范化?为什么要将 col 值存储为行。尝试对 table1 进行非规范化,使其具有第一列和最后两列。这将是最好的解决方案。

另外,你在 id 和 tag 列上有正确的索引吗?如果是,那么合并连接非常适合您的查询。

请提供这些表的索引详细信息以及您的查询生成的计划。

您的查询将像内部连接查询一样使用。

select table2.occupation, first.valkue as first, last.value as last 
from 
table2
inner join table1  first 
on first.tag = 'first'
and first.id =table2.id
inner join table1 last
on last.tag = 'last'
and table2.id = last.id 

【讨论】:

  • 我的示例是我正在使用的实际 sql 的一个非常简单的表示。真实的东西加入了 8 个左右的表,并且有很多很多基于用户过滤选择的动态条件。这里没有要优化的查询。至于垂直表的规范化,嗯,是的,在一个理想的世界里也许我可以这样做,但它是一个垂直表是有原因的,除了第一个和最后一个之外还有很多字段,这些字段的数量和类型取决于各种其他用户选择的东西。无法展平为表格中的一组列。
  • 这很好,但扁平化查询比物化查询要好。你能告诉我哪些列有索引吗?你能发布计划吗?你使用哪个版本?如果没有计划发布统计信息io,时间详情?
  • 非常复杂,可能是公司机密,所以我不能这样做,抱歉。
  • 好吧,为什么你认为你的查询很慢?
【解决方案2】:

我有点困惑。您的查询看起来不错。 . .尽管使用正确的连接语法看起来更好。

select table2.occupation, firsttable.first, lasttable.last
from table2 join
       (select value as first from table1 where tag = 'first') firsttable
       on table2.id = firsttable.id join
       (select value as last from table1 where tag = 'last') lasttable
       on table2.id = lasttable.id 

此查询执行您要求它执行的操作。 SQL 是一种声明性语言,而不是过程性语言。这意味着您描述结果集并依靠数据库 SQL 编译器将其转换为正确的命令集。 (也就是说,有时查询的结构确实会使某些引擎更容易或更难生成有效的查询计划。)

【讨论】:

  • 答案是他的查询看起来不错。我不明白问题是什么。该条件已在查询中。
  • 问题是,有没有更好的方法来制作派生表,或者我可以使用其他东西来限制派生表的大小以提高效率。这是一个简单的例子,真正的查询在 where 子句中有更多的字段和更多的表达式,这可能会使查询变得更好或更糟。
  • 我明白了。答案基本上是“不”。 Sybase 将查询编译成它自己的内部表示,理论上,给定它所拥有的信息,它应该是最好的查询计划。有时引擎是错误的,您可以调整它们,但您的查询很好。如果您有关于查询计划和性能的具体问题,则应将其作为单独的问题发布。
【解决方案3】:

我认为您要的是COMMON TABLE EXPRESSION。如果您的平台没有实现它们,那么临时表可能是最好的选择。

【讨论】:

  • 我查了 CTE,你是对的,听起来是这样。但基于此,sybase 15 不支持它...*.com/questions/4803573/…
  • 那么临时表可能是您唯一的选择。当然,Sybase 中的 SQL 优化器可能足够聪明,只计算一次……你检查过吗?
  • 经过一番查看(我只提出了这个问题,因为查询需要 15 秒才能运行)我意识到 sybase 正在对一个相当大的表进行表扫描,当我完全删除一个单独的表时不相关的连接查询在 5 秒内运行,即使有 2 个派生表,所以现在我认为派生表不是问题,但我仍然想知道是否有更好的方法来做派生表,它听起来像 CTE 是它。谢谢。