0

select条件とwhere条件の両方にある数式を1回だけ計算する方法はありますか?

次の例では、mysql は行ごとに 2 回計算を行う必要があると思います。

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が前に評価されるためです。SELECTSELECT

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) よりも高速です
  • 平方根を計算する代わりに、反対側を平方できます。

試す:

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 乗していますが、POW の結果に実際には影響しないため、ここでは ABS は必要ありません。

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 に答える