2011-03-06 44 views
1

我有一個系統,它將從數據庫中返回所有用戶,並按距參考郵政編碼最小的距離排列結果。按照郵政編碼距離的升序對用戶進行計算和排序的最快方法

例如:用戶會在網站上,輸入郵政編碼,它會回報他最近誰是他的拉鍊(升序)

爲什麼我現在做的這一切其他用戶,爲什麼它一個問題 ?

該系統包含超過3000萬用戶及其郵編。我正在搜索特定州和城市的所有用戶(將數據集縮小到約10,000)。

這是實際發生問題的地方。現在,mysql(10,000)行發送給PHP的所有結果都會發送到一個郵政編碼計算器庫,它可以計算基本郵政編碼和用戶郵政編碼之間的距離 - 10,000次。然後通過最接近的郵政編碼對結果進行排序。

正如你所看到的,這是非常糟糕的優化代碼。 10,000條記錄通過兩次循環。更不用說每個httpd進程只需將數據傳遞給mysql的RAM數量。

我想問一下這裏的專家有沒有優化這個?

我有一些我自己的想法,但我不確定它們的效率。

試着做所有的郵編計算和在MySQL本身的順序,並返回分頁的行數。 爲此,我需要將郵政編碼計算邏輯與存儲過程之間的距離。這樣我就可以防止在PHP中處理10,000條記錄。但是,仍然存在問題。我不需要計算已經計算出的郵政編碼的距離(對於具有相同郵政編碼的2個用戶)。

其次,我如何在MySQL中使用存儲過程命令行?

你們認爲什麼?這是一個好方法嗎?我可以期待使用它的性能提升嗎? 你有其他建議嗎?

我知道這個問題是巨大的,我真的很感激你讀到最後的時間。我真的很想聽聽你對此的想法。

回答

1

因爲我不太熟悉PHP或MySQL,我只能給出一些基本的提示,但他們應該幫助。這也假定你沒有直接的方式與MySQL的zip庫連接。

首先,這是值得懷疑的,你必須在一個城市10K郵政編碼,把你現有的查詢,並完成類似

SELECT DISTINCT ZipCode FROM Users WHERE ... 

這可能會返回幾十郵政編碼最大,並沒有重複。通過您的郵政編碼庫運行此操作。這個庫本身可能是一個緩慢的來源,因爲它必須查找郵政編碼,並做一堆花式觸發來獲得實際的距離。拿這個的結果,並將它插入到一個只有郵編和距離的臨時表中。

一旦完成了該列表,就可以擁有另一個查詢來獲取所需的其他用戶數據,然後加入郵政編碼的臨時表以獲取距離。

這應該會給你相當大的加速。計算結果後,您可以在第二個查詢中進行所需的分頁。並沒有更多的循環10k行。

0

如果你可以獲得所有郵編的經緯度到MySQL,或者有一個簡單的方法來獲取你的基本郵政編碼的緯度/經度,並將其提供給你的MySQL查詢,那麼你可以通過距離命令你的10k用戶在MySQL裏面。有一個very similar question and answer here它給你距離函數的正確數學。您可能還想調查Mysql spatial extensions,這將允許您插入並將您的經緯度作爲2D POINT數據編入索引。

+0

我已經有一個郵政編碼表,它在美國和它們各自的緯度/經度都有everyzip代碼。這會有幫助嗎? – 2011-03-06 22:06:16

1

我建議您在爲過濾和排序目的計算精確距離之前縮小經度和緯度範圍。

我的意思是說,如果您執行全表掃描並計算數據庫中所有郵政編碼相對於您的參考點的距離,它將非常緩慢。

相反,通過接近過濾郵政編碼。我的意思是如果你的緯度是10和20,那麼首先計算你想要的接近度的最大角度範圍。比方說你想要一個10英里的距離範圍。這可能會轉化爲0.15度。因此,您需要過濾郵政編碼,第一個緯度在10-0.15和10 + 0.15之間,經度在20-0.15和20 + 0.15之間。

只有在此之後,您才能在SQL查詢條件中包含準確的距離子句。這將更快,因爲您不再進行全面掃描,並且最終可以在經度和緯度字段上使用範圍索引。

要將英里轉換爲度數找到狹窄範圍,請記住,地球有25,000英里的周長,將25000分成360度,每度可達70英里。如果你想要一個10英里的範圍,你的範圍最多是0.15度。

請記住,這些計算是不準確的(地球不完全圓整),但這並不重要。重要的是,您發現的度數範圍值比真實的準確值要高。

相關問題