2009-12-04 93 views
2

我有問題。我有500k記錄的數據庫。每個記錄存儲緯度,經度,動物種類,觀察日期。我必須在mapkit視圖之上繪製網格(15x10),顯示這個網格單元中物體的濃度。每個單元格都是32x32的盒子。iPhone硬計算和緩存

如果我在運行時計算它非常慢。 有人想法如何緩存它?在內存或數據庫中。

數據結構:

觀察:

  • 緯度
  • 經度
  • 日期
  • 正金
  • 一些其他不重要的數據

屏幕示例:在該區域中的物種

alt text http://img6.imageshack.us/img6/7562/20091204201332.png

每個紅色框opocasity節目計數。我現在使用

代碼: 數據 - >從數據庫中選擇,它是在地圖區域內的所有觀察

for (int row = 0; row < rows; row++) 
{ 
    for (int column = 0; column < columns; column++) 
    { 
    speciesPerBox=0; 
    minG=boxes[row][column].longitude; 
    if (column!=columns-1) { 
    maxG=boxes[row][column+1].longitude; 
    } else { 
    maxG=buttomRight.longitude; 
    } 

    maxL=boxes[row][column].latitude; 
    if (row!=rows-1) { 
    minL=boxes[row+1][column].latitude; 
    } else { 
    minL=buttomRight.latitude; 
    } 

    for (int i=0; i<sightingCount; i++) { 
    l=data[i].latitude; 
    g=data[i].longitude; 

    if (l>=minL&&l<maxL&&g>=minG&&g<maxG) { 
    for (int j=0; j<speciesPerBox; j++) { 
     if (speciesCountArray[j]==data[i].specie) { 
     hasSpecie=YES; 
     } 
     } 

     if (hasSpecie==NO) { 
     speciesCountArray[speciesPerBox]=data[i].specie; 
     speciesPerBox++; 
     } 

     hasSpecie=NO; 


    } 
    } 
    } 


    mapData[row][column].count = speciesPerBox; 
    } 
} 
+1

另外,您確定您的數據庫密鑰適合您的查詢嗎? – 2009-12-04 18:55:42

+0

這是你的意思嗎? – 2009-12-04 19:56:43

回答

4

既然你的數據是靜態的,你可以預先計算每個網格和存儲每個物種它在數據庫中而不是所有的位置座標。

由於您有15 x 10 = 150個單元格,您將以數據庫中的150 * [物種數]記錄結束,這應該是一個更小的數字。

此外,請確保您有正確的列索引。否則,您的查詢將不得不一遍又一遍地掃描每一條記錄。

+0

如果用戶縮放地圖我需要重新計算所有這些數據,並且用戶可以通過觸摸移動地圖,我還需要重新計算它。 – 2009-12-04 18:52:08

+3

你有多少個縮放級別?預先計算最高級別的縮放(因爲它們是計算成本最高的)。如果允許用戶任意縮放,則不能真正減少所需的計算。您的問題超出了iPhone的容量。 – 2009-12-04 18:55:13

+0

是的,我在想。 – 2009-12-04 18:56:31

1

循環for (int i=0; i<sightingCount; i++)正在扼殺你的表現。尤其是大量的if (l>=minL&&l<maxL&&g>=minG&&g<maxG)報表,其中絕大多數的發現將被跳過。

瞄準量有多大?

第一個你應該使用一種空間優化,例如,一個簡單的:每個細胞存儲物種數量列表(讓我們稱之爲「區域」)。將這些區域定義爲相當大,以免浪費空間。但較小的區域提供更好的性能,而太小的區域會扭轉效果。因此,使其可配置並測試不同的區域大小以找到一個好的折中!

當總結細胞中物種的數量進行渲染時,確定給定細胞重疊的區域(相當簡單和快速的「矩形重疊」測試)。那麼你只需要檢查這些區域的物種數量。這大大減少了你的內部循環的迭代!

這就是大多數「空間優化」的想法:分而治之;在這裏你將劃分你的空間,然後你可以儘早地拒絕大量不相關的「目擊」的處理,而只需很少的努力(增加的努力是矩形重疊測試,但是每個測試拒絕多次目擊,你當前的代碼測試每個單獨的瞄準相關)。

第二步,也應用一些明顯的代碼優化:例如, minL和maxL不會更改每列。計算minL和maxL可以移動到外部循環(就在​​之前)。

由於網格的緯度均勻分佈,您甚至可以將它們從網格單元中移除,這樣可以在迭代過程中節省一些時間。這裏一個例子(不包括空間優化):

maxL=boxes[0][0].latitude; 
minL=boxes[rows-1][0].latitude; 
incL=maxL-minL; 
for(int row = 0; row < rows; row++) 
{ 
    for(int column = 0; column < columns; column++) 
    { 
     speciesPerBox=0; 
     minG=boxes[row][column].longitude; 
     if (column!=columns-1) { 
      maxG=boxes[row][column+1].longitude; 
     } else { 
      maxG=buttomRight.longitude; 
     } 
     ... 
     ... 
    } 
    ... 

    minL = maxL; // left edge = right edge of previous step 
    maxL += incL; // increment right edge 
    if(maxL >= 90) maxL -= 90; // check your scale, i assume 90° 
} 

也許這也適用於經度循環,但經度可能不能均勻地分佈(即「INCG」是在各步驟中不同)。

請注意,空間優化將產生巨大的差異,循環優化只有一個小的(但仍然值得)的差異。

+0

sightingCount - 在最大的情況下是500-600k – 2009-12-04 19:51:56

+0

好的。那麼你應該使用空間優化。 – Frunsi 2009-12-04 20:21:42

1

對於500k條記錄,這聽起來像是核心數據的工作。最好是桌面上的核心數據。如果數據沒有實時更新您應該在較重的硬件上處理數據,並使用iPhone來顯示它。這將大大簡化應用程序,因爲您只需存儲每個地圖單元格的值。

即使您確實想在iPhone上處理它,您也應該讓應用程序處理一次數據並保存結果。似乎沒有理由讓應用程序在每次顯示單元時重新計算每個地圖單元的物種價值。

我建議在覈心數據中創建一個實體來表示觀察值。然後是另一個實體來表示地理方塊。設置廣場和落在廣場內的觀測值之間的關係。然後在方形實體中創建物種的計算值。如果其中一個觀測值發生變化,那麼您只需重新計算物種的價值。

這是對象圖創建的那種問題。即使數據正在不斷更新。核心數據只會執行所需的計算,以適應在任何給定時間發生變化的少量觀察對象,並且它將以高度優化的方式進行。

Edit01:

從完全不同的角度接近的問題。在覈心數據內。 (1)創建觀察記錄的對象圖,使得每個觀察對象與地理上最接近它的其他觀察對象具有互逆關係。這將創建一個對象圖,看起來像一個扁平的不規則網。 (2)爲觀察記錄類創建方法,該觀測記錄類(a)確定記錄是否落在任意地理方格的邊界內(b)詢問它的每個記錄是否也在方格內(c)返回自己的物種數量和所有相關記錄的數量。

(3)將你的地圖劃分成一些合理的小方塊,例如一秒鐘的弧形廣場。在該方塊內選擇一個鏈接記錄並將其添加到列表中。選擇百分比的所有記錄,比如每100或1,000個記錄中的一個,以便將列表從500k減少到創建一個可以通過蠻力謂詞快速搜索的子列表。讓我們在列表中調用這些記錄gridflags。

(4)當用戶放大時,使用蠻力來查找所有具有地理柵格的柵格記錄。然後要求每個gridflag記錄向每個鏈接記錄發送消息,以查看(a)它們是否在網格中,(b)它們的物種數量是多少,以及(c)它們的鏈接記錄的計數是多少在網格內。 (使用一個標誌確保每條記錄僅在每次搜索時被查詢一次,以防止失控遞歸)。

這樣,您只需在每個任意大小的網格單元內找到一條記錄,並且該記錄將查找所有其他記錄爲你。而不是逐步查看每條記錄,以查看每條記錄每次進入哪個單元格,而只需處理每個單元格和那些緊鄰的單元格中的記錄。放大時,您實際查詢的記錄數量會縮小,而不會保持不變。如果網格單元格只有少數記錄,則只需查詢一些記錄。

這需要一些努力和時間來設置,但一旦你做了,它將是相當有效的,尤其是當放大方式。對於頂級,只需要一個預處理的靜態地圖。

希望我解釋得不錯。口頭傳達很難。

+0

我在項目中使用核心數據,但原始sql查詢更快。 問題是框座標和大小取決於地圖區域,這改變了用戶。 – 2009-12-04 22:17:22