是否可以将 SELECT 中的多个乘法分解为仅对所有行执行一次



假设我有以下SQL查询,涉及"AS..."的浮点运算阶段。

SELECT
T1.A * T2.B *  T1.D1 * T3.C AS A1
T1.A * T2.B *  T1.D2 * T3.C AS A2
(...)
T1.A * T2.B * T1.D100 * T3.C  AS A100
FROM TableName1 as T1
INNER JOIN TableName2 AS T2
LEFT JOIN  TableName3 AS T3

其中 TableName 有 5.000.000 行,A、B C 和 D 是 A 中的行,每行不同。 2 问题 :

1 - A * B * C会实际执行100次吗?2 - 有没有办法分解 A * B * C 运算,以便对一行的 100 列仅执行一次的 2 次循环乘法?

此外,我们可以认为"B"将是一个复杂的函数调用(SQRT(ARTCTAN(...(x))),因此每只想执行一次的合法性。

我认为它会预先计算它可以计算的内容(SQL Server),然后将其应用于列。

我很确定,如果您将相乘的数字放在单行交叉连接的选择中,那就可以了。 像这样:

select D1 * res
from tableName
cross join (select A * B * C as res) as multiplied

编辑

如果数据在列中,而不是标量值中,那么可能是:

select t1.D1 * myAlias.res, t1.D2 * myAlias.res, t1.D3 * myAlias.res
from tableName t1
inner join 
    (
    select t2.keyCol, t2.A * t2.B * t2.C as res
    from tableName t2
    ) myAlias 
on t1.keyCol = myAlias.keyCol

一种方法可能是在表上创建计算列。在SQL Server中,这看起来像这样:

CREATE TABLE TableName
 (
   A  float  not null
  ,B  float  not null
  ,C  float  not null
  ,AxBxC  AS  A * B * C
 )

该列将(好吧,应该,这取决于RDBMS是如何实现的)每读取一行计算一次,然后每次使用。作为校准列,公式为表存储一次,因此不会显著增加存储空间。


更新问题:

您现在正在执行涉及 5,000,000 行的三向表联接(一个外联接,不少)。这将很容易达到 10 兆字节,也许是 100 兆字节的磁盘 I/O(除非数据是从先前的读取中缓存的),并且需要合并、循环、哈希连接等来链接所有数据。到完成所有这些操作时,相比之下,执行算术所需的CPU量将是微不足道的。CPU擅长数学。

要对此进行测试,请执行以下操作:

  • 构建并运行"完整"查询,如您的问题中所述
  • 生成并运行返回 A * B* C 计算的查询。
  • 采用"calc once"查询,并将其用作联接到"base"查询的子查询或临时表。

最后一种方法是我能想到的强制SQL每行只执行一次计算的唯一方法。但是,这会带来额外的联接(跨越 500 万行),从我所见过或读到的所有内容来看,这就是您的性能受到最大影响的地方。

(如果你做这个测试,我会非常感兴趣地看到结果!

最新更新