0

有没有办法让一个公式在 select 和 where 条件中只计算一次?

我假设 mysql 必须对每一行进行两次计算,如下例所示。

SELECT z1.id sid1,z2.id sid2,SQRT(POW(ABS(z1.col-z2.col),2) + POW(ABS(z1.row-z2.row),2)) r
    FROM stars z1,stars z2
    WHERE z1.id!=z2.id
    AND SQRT(POW(ABS(z1.col-z2.col),2) + POW(ABS(z1.row-z2.row),2)) <=32
    ORDER BY z1.id,z2.id
4

2 回答 2

2

您不能在子句中引用在SELECT子句中定义的别名WHERE,但可以在HAVING子句中使用它们。这是因为WHERE之前评估过SELECT可能SELECT包含聚合函数。

SELECT z1.id sid1,z2.id sid2,SQRT(POW(ABS(z1.col-z2.col),2) + POW(ABS(z1.row-z2.row),2)) r
 FROM stars z1,stars z2
 WHERE z1.id != z2.id
 HAVING r <= 32
 ORDER BY z1.id,z2.id

但请注意,该HAVING子句很可能不会在索引中使用。您可以为该WHERE子句提供一个近似术语以用于索引目的:

SELECT z1.id sid1,z2.id sid2,SQRT(POW(ABS(z1.col-z2.col),2) + POW(ABS(z1.row-z2.row),2)) r
 FROM stars z1,stars z2
 WHERE z1.id != z2.id
 AND (z2.col BETWEEN z1.col-32 AND z1.col+32)
 AND (z2.row BETWEEN z1.row-32 AND z1.row+32)
 HAVING r <= 32
 ORDER BY z1.id,z2.id

请注意,瓶颈是磁盘访问,而不是算术计算,因此如果您正在优化速度,您可能希望保留 WHERE 并仅优化 WHERE 子句:

注意

  • x^2 与 abs(x)^2 相同。
  • x*x 可能比 pow(x,2) 快
  • 您可以将另一边平方而不是计算 sqrt。

尝试:

SELECT z1.id sid1,z2.id sid2,
  SQRT((z1.col-z2.col)*(z1.col-z2.col) + (z1.row-z2.row)*(z1.row-z2.row)) r
 FROM stars z1,stars z2
 WHERE z1.id != z2.id
 AND (z1.col-z2.col)*(z1.col-z2.col) + (z1.row-z2.row)*(z1.row-z2.row) <= 1024
 ORDER BY z1.id,z2.id
于 2012-11-28T07:17:33.633 回答
0

请注意,您实际上不需要计算此表达式

SQRT(POW(ABS(z1.col-z2.col),2) + POW(ABS(z1.row-z2.row),2)) <=32

首先,您可以通过将表达式的两个部分都提高到 2 次方来避免计算 SQRT,这通常是缓慢且不是绝对准确的。之后它变为相等,但更准确和更快

POW(ABS(z1.col-z2.col),2) + POW(ABS(z1.row-z2.row),2) <= 1024

其次,您将 ABS(z1.col-z2.col) 提高到 2 次方,但这里不需要 ABS,因为它不会真正影响 POW 的结果。

z1.col = 4, z2.col = 2   => pow(4-2, 2) = pow(2,2) = 2*2 = 4
z1.col = 2, z2.col = 4   => pow(2-4, 2) = pow(-2,2) = -2*-2 = 4

所以,

POW(z1.col-z2.col,2) + POW(z1.row-z2.row,2) <= 1024

将使查询更快。

于 2012-11-28T07:40:57.707 回答