2011-09-26 71 views
0

我有一個汽車的分類列表網站,我正在開發使用PHP開發的過程。用戶使用主頁上的下拉選項框輸入他們正在尋找的汽車的詳細信息。當他們點擊提交時,他們被帶到結果頁面,這是我遇到問題的地方。有關SQL查詢速度和性能問題的幫助

它是建立在目前的方法是:

  1. 數據庫中查詢他們正在尋找汽車匹配任何結果。查詢返回汽車的ID和廣告的郵政編碼;
  2. 然後檢查每個廣告的用戶郵政編碼和廣告郵政編碼之間的距離。這本身需要數據庫查詢來查找每個廣告的單個郵政編碼的座標,並且對於有時可能超過350個結果的相當耗時;
  3. 然後使用if語句來確定距離是否小於或等於用戶在主頁上輸入的距離
  4. 如果廣告在允許的距離內,則它的ID被添加到數組;
  5. 然後計算該陣列中的廣告總數,並用於確定取決於廣告數量和要在頁面上顯示的廣告數量的變量;
  6. 然後使用WHERE語句和數組中的ID執行廣告表的第二個查詢。例如SELECT * FROM adverts WHERE ID=1 AND ID=4 AND ID=23 ........查詢中使用的ID的總數取決於第5點中提到的變量。然後,當用戶單擊下一頁時,將從數組中剩下的位置重新運行查詢然後查詢被重新創建並執行。

我遇到的問題是,它需要很長時間才能完成,我正在尋找更多的資源和時間完成它的有意識的方式。

它最初被設計爲用WHERE子句爲每個用戶對汽車的特定要求執行查詢,然後在輸出到頁面之前使用if語句檢查距離。這造成了頁面編號的問題,因爲無法確定與查詢中返回的廣告的距離要求相匹配的廣告數量 - 因此,在完整廣告被收集之前滿足距離條件的情況下這樣做計算要顯示的確切數量的廣告。

對不起,它有點長 - 希望它是有道理的。我沒有包含任何代碼,因爲它會讓它變得更長,而且它的邏輯問題與實際代碼相反。

感謝您提出的任何建議。

有人要求表佈局和SQL。開始.....

廣告表

ID,品牌,型號,顏色,里程,發動機,年份,郵編

郵編表

ID,郵編,GridN,GridE,經度,緯度

用於首次查詢以獲得ID和郵政編碼的SQL

SELECT ID, Postcode FROM adverts WHERE Make = '$subMake' AND Model = '$subModel'

SQL第二查詢來獲得使用符合距離要求,該ID的該廣告的詳細信息:

SELECT Make, Model, Year, Engine, Colour FROM adverts WHERE ID IN(1,2,6,90,112,898) 

(很抱歉,如果它不是語法正確的,它的工作,即SQL只是查詢字符串的許多行的粗略輪廓)。

+5

'SELECT * FROM adverts WHERE ID = 1 AND ID = 4 AND ID = 23' would always always returns 0 rows?你的意思是'SELECT * FROM adverts WHERE ID IN(1,4,23)'instead? – GordonM

+1

某些答案最少需要的是表結構和您正在使用的SQL ... – Yahia

+2

是不是可以在您的SQL語句中執行距離計算,然後在返回之前進行篩選?這會快很多...... – Paddy

回答

0

最大的優化是查詢郵政編碼表並將網格引用存儲在廣告表中 - 當您插入廣告行時。

這將大大減少對郵政編碼表的訪問次數。

您還可以通過在廣告表上進行一些簡單過濾來減少計算次數,如下所示。

從郵政編碼表中獲取用戶GridN和GridE值。 計算minN爲GridN - maxDistance,maxN爲GridN + maxDistance,minE爲GridE - maxDistance,maxE爲GridE + Maxdistance。

然後,您可以在廣告表中查詢,像這樣:

SELECT * FROM ADVERTS WHERE GridN between (minN,maxN) and GridE Between(minE,maxE); 

爲了進一步加快這您可以添加索引GridN和GridE。

一旦您選擇了行,您就可以計算「真實」距離並拒絕超出極限的幾行。

+0

感謝這個答案,聽起來像它正是我需要的 - 我將在今天晚些時候實施它。我難以理解的是,它究竟如何計算距離。我習慣用三角函數來計算它。這種方式如何工作?謝謝 – Max

+0

你並沒有真正計算遠程,你正在選擇一個完全包含「圈子」的地理「方塊」,該圈子定義了客戶端的x英里。會有點向廣場的角落落在圈外。 I.E.如果您的用戶在10英里範圍內選擇了廣告,則此查詢仍然會選擇位於您的客戶以東9.9英里和東部9.9英里處的實際距離爲14英里的添加 - 您需要進一步進行三角計算以拒絕這些離羣值。但是,您已經通過簡單比較有效地消除了99%的廣告! –

+0

用於計算最小和最大距離的距離,除非我使用高於3000的數字,否則返回結果,然後隨着距離的增加顯示更多的距離。我是否必須改變距離測量單位的單位?除此之外,它已經加快了x10的整個過程。謝謝!! – Max

0

修改查詢,使其包含郵政編碼之間的距離,並限制爲指定距離範圍內的廣告。

+0

Hi @mark這樣做的問題是距離不在任何表中,因此無法查詢。這個距離是根據每個用戶在頁面上計算出來的,並帶有一個函數,該函數接受兩個郵政編碼(廣告郵政編碼和用戶郵政編碼),然後返回一個距離,然後檢查該距離。 – Max

+0

Hi @Max。確定距離的函數可以作爲用戶定義的函數在數據庫中創建嗎? –

+0

這裏的問題是你需要在每一行上做小學畢達哥拉斯計算「x平方和y平方和的平方根」。平方根的計算是什麼吃的時間。 –

0

您應該將距離函數轉換爲具有所有可能的郵編組合的視圖,然後您可以在查詢中加入該距離函數而不是擊中該函數,或者可以計算距離用戶帖子50公里的緯度和經度代碼

除此之外,如果您提供固定選項(這些網站大部分僅提供5,10,25,50,100作爲距離選項),那麼您可以預先計算這些距離計算並進一步去如果你真的想要做附加檢查並將每個郵政編碼映射到附近的所有郵政編碼,那麼你只需要爲每個郵政編碼計算5次(5個距離),並且可以從前一個值中排除結果,這樣你從10km查詢中排除5km,因爲您有理尋找距離< = 10公里。

0

根據你的數據庫,也許使用類似PostGIS的東西?

在Adverts表中爲LonLat數據類型設置一個列,然後運行內置函數(如ST_DWithin)以便在距目標記錄指定距離內找到所有具有LonLat的廣告。

只是指出我發現使用靜態郵編數據庫的另一個問題是,它們很快就會過時(特別是對於新版本)。您可能還想使用Mapstraction之類的功能來返回來自Google/Yahoo等的地理編碼結果,並保存該LonLat - 儘管您可能必須對郵政編碼輸入進行更多錯誤檢查並將返回的結果限制爲完全匹配。