如何在一次计算中选择和过滤公式

时间:2012-11-28 07:10:15

标签: mysql select where

有没有办法让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

2 个答案:

答案 0 :(得分:2)

您不能引用SELECT子句中WHERE子句中定义的别名,但可以在HAVING子句中使用它们。这是因为WHERESELECT之前进行了评估,因为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

答案 1 :(得分: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

会使查询更快。