2010-11-11 51 views
3

我是新來的整個PHP/MySQL的東西。我有一週的服務器日誌(約300,000項),我需要做一些分析。我打算將它們全部讀入一個mysql數據庫,然後用php進行分析。PHP/MYSQL:遍歷數據庫中的每條記錄

我不確定的事情是如何迭代它們。使用java讀取文件我會做這樣的事情:

Scanner s = new Scanner(myfile); 
while(s.hasNext()){ 
    String line = s.nextLine(); 
    ~~ Do something with this record. 
} 

如何使用PHP迭代MySQL數據庫中的所有記錄?我認爲這樣的事情會佔用一些愚蠢的內存。

$query = "SELECT * FROM mytable"; 
    $result = mysql_query($query); 
    $rows = mysql_num_rows($result); 
    for($j = 0; $j < $rows; ++$j){ 
      $curIndex = mysql_result($result,$j,"index"); 
      $curURL  = mysql_result($result,$j,"something"); 
      ~~ Do something with this record 
    } 

所以我增加了一個限制選擇語句,我重複,直到所有記錄已經循環。有沒有更標準的方法來做到這一點?有沒有內置的,會做到這一點?

while($startIndex < $numberOfRows){ 

    $query = "SELECT * FROM mytable ORDERBY mytable.index LIMIT $startIndex,$endIndex"; 
    $result = mysql_query($query); 
    $rows = mysql_num_rows($result); 
    for($j = 0; $j < $rows; ++$j){ 
      $curIndex = mysql_result($result,$j,"index"); 
      $curURL  = mysql_result($result,$j,"something"); 
      ~~ Do something with this record 
    } 
    $startIndex = $endIndex + 1; 
    $endIndex = $endIndes + 10; 
} 

回答

4

在這裏看到:

http://www.tizag.com/mysqlTutorial/

http://www.tizag.com/mysqlTutorial/mysqlfetcharray.php

<?php 
// Make a MySQL Connection 
$query = "SELECT * FROM example"; 

$result = mysql_query($query) or die(mysql_error()); 


while($row = mysql_fetch_array($result)){ 
    echo $row['name']. " - ". $row['age']; 
    echo "<br />"; 
} 
?> 

根據您需要的結果行做什麼,你可以使用不同的環路的風格,無論是其' while','for each'或'for x to x'。大多數時候,一個簡單的'while'迭代將會很好,而且效率很高。

+0

這不會使用瘋狂的內存量嗎?這是否有一些基本的方法來獲取需要的東西? – sixtyfootersdude 2010-11-11 14:34:57

+0

任何過濾器都應該應用到底層的SQL,SQL語句應該只產生所需的記錄,然後PHP會爲您的目的迭代,如果您有大數據集,請考慮使用單獨的'頁面' – SW4 2010-11-11 14:46:05

+0

Re:內存,如果你需要使用所有返回的記錄(如果你沒有,然後調整你的SQL),這些都是內置的PHP函數,所以可能是最好的方法 – SW4 2010-11-11 14:47:03

2

使用mysql_fetch_*

$result = mysql_query(...); 
while($row = mysql_fetch_assoc($result)) { 
$curIndex = $row['index']; 
} 

我想在一個「流」的方式檢索結果,而不是將它們全部加載到內存中一次。我不確定mysql_result究竟做了什麼。

注意:由於您還是新手,我建議您立即進入良好的使用習慣,並立即跳過mysql_的功能,並去PDO或至少mysqli

+0

爲什麼使用PDO或mysqli更好?這是標準還是冬青戰爭? – sixtyfootersdude 2010-11-11 14:32:22

+0

查找的一般術語是對象關係映射(ORM)。有不同的或多或少的標準,但我不認爲這是一場神聖的戰爭。一方面有OO,另一方面是關係形式主義,你需要一些映射是很自然的。而不是手工做這件事總是一件好事。 – Frank 2010-11-11 14:49:27

+0

@Frank:PDO和mysqli都不和ORM有任何關係,恐怕它們只是提供了一個到數據庫連接的OO接口,數據仍然是一如既往的關係。 – 2010-11-11 15:54:05

5

如果你的表很大,你不想做一個SELECT * FROM MYTABLE,你會把所有的東西放在內存中。內存開銷和數據庫調用之間的折衷是批量請求。從minId

SELECT MIN(ID) FROM MYTABLE; 
SELECT MAX(ID) FROM MYTABLE; 

現在環路maxId,通過增加每說一次10000:你可以得到行的最小和最大的ID在表格中。在僞代碼中:

for (int i = minId; i < maxId; i = i + 10000) { 
    int x = i; 
    int y = i + 10000; 
    SELECT * FROM MYTABLE WHERE ID >= x AND ID < y; 
} 
+0

這就是我在第三個例子中使用'LIMIT'所做的事情,除了我的解決方案允許結果被ID以外的東西排序。 – sixtyfootersdude 2010-11-11 14:33:26

+0

我的版本更高效,因爲您只需拉出x和y之間的行。使用LIMIT,您將取出所有內容,然後獲取您的開始和結束ID指定的任何行(此處的startIndex和endIndex ID不是表的主ID,而是前面生成的結果的行號查詢) – 2010-11-11 14:39:09

+0

好吧,我買了。這只是一個MYSQL優化。 – sixtyfootersdude 2010-11-11 18:25:47

0

在理想的世界中,PHP會生成聚合查詢,將它們發送到MySQL,並且只返回少量的行。例如,如果您要計算兩個日期之間每個嚴重級別的日誌項數量:

SELECT COUNT(*), severity 
FROM logs 
WHERE date < ? AND date > ? 
GROUP BY severity 

在PHP方面做的工作非常不尋常。如果你發現你需要的SQL查詢處理過於複雜(因爲你可以控制你的數據庫結構,給你很大的自由度),更好的選擇是移動到Map-Reduce數據庫像CouchDB這樣的引擎。

0

我堅信用Doctrine或任何類型的MySQL迭代(PDO或mysqli)進行批處理只是一種幻想。

@ dimitri-k提供了一個很好的解釋,特別是關於工作單元。問題是導致錯過:「$ query-> iterate()」,它並不真正迭代數據源。它是只是一個\ Traversable包裝左右已經完全提取數據源。

證明,即使從圖片完全去除主義抽象層,我們仍然會碰到內存的例子發出

echo 'Starting with memory usage: ' . memory_get_usage(true)/1024/1024 . " MB \n"; 

$pdo = new \PDO("mysql:dbname=DBNAME;host=HOST", "USER", "PW"); 
$stmt = $pdo->prepare('SELECT * FROM my_big_table LIMIT 100000'); 
$stmt->execute(); 

while ($rawCampaign = $stmt->fetch()) { 
    // echo $rawCampaign['id'] . "\n"; 
} 

echo 'Ending with memory usage: ' . memory_get_usage(true)/1024/1024 . " MB \n"; 

輸出:

Starting with memory usage: 6 MB 
Ending with memory usage: 109.46875 MB 

在這裏,令人失望getIterator()方法:

namespace Doctrine\DBAL\Driver\Mysqli\MysqliStatement 

/** 
* {@inheritdoc} 
*/ 
public function getIterator() 
{ 
    $data = $this->fetchAll(); 

    return new \ArrayIterator($data); 
} 

您可以使用我的小型庫到實際上使用PHP Doctrine或DQL或純粹的SQL流重型表。但是你找到合適的:https://github.com/EnchanterIO/remote-collection-stream

相關問題