2012-11-28 63 views
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 
+0

我不擔心數學運算的表現。 –

+0

我並不確定,但是當你爲SQRT(POW(ABS(z1.col-z2.col),2)+ POW(ABS(z1.row-z2.row))創建一個別名'r'時, 2)),你不能只是做'AND r <= 32'嗎? –

+0

@Kohányi一直在嘗試,但不能得到它的工作 – Mahks

回答

2

你不能指在一個WHERE子句SELECT條款定義的別名,但你可以在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子句:

注意到

  • X^2是相同的ABS(x)的^ 2。
  • x * x可能會比po​​w(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 
+0

工作,但查詢執行時間加倍!? – Mahks

+1

@Mahks嘗試通過[MySQL的'EXPLAIN'](http://dev.mysql.com/doc/refman/5.5/en/explain)運行你的查詢(有或沒有'HAVING')。html)找出爲什麼一個比另一個慢。 –

+0

我用任何一種方法都能得到同樣的報告,但是我不明白我所看到的是什麼 – Mahks

0

請,請注意,你並不真的需要計算這個表達式

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

首先,你可以避免計算SQRT,這是一般,慢而不是絕對準確,通過提高這兩個表達部分的權力2.在此之後,它變得相等,但更準確和快速

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 

將作出查詢快得多。

+0

速度只有邊際增加。 – Mahks

+0

取決於桌子的大小。你可能不會填滿10,000。無論如何,正如Jan Dvorak所說,真正的MySQL瓶頸是從磁盤讀取文件 –