2014-05-22 3 views
1

나는 1500 명의 사람들을위한 실험 결과를 담고있는 큰 데이터베이스를 가지고있다. 각 개인은 96 개의 데이터 포인트를 가지고 있습니다. 분석 소프트웨어에서 사용할 수 있도록 데이터를 요약하고 형식을 지정하기 위해 다음 스크립트를 작성했습니다. 처음에는 500 명이 넘을 때까지 모두 좋았습니다. 이제 나는 기억이 부족하다.mysql에서 제한된 메모리로 큰 결과 집합을 처리하기

누군가가 속도를 희생하지 않고 메모리 제한 문제를 극복하기위한 제안을 갖고 있는지 궁금합니다.

이 데이터베이스의 테이블 모습

fishId assayId 그래서이 데이터베이스에 대한 호출입니다

14_1_1 2 AA

$mysql = new PDO('mysql:host=localhost; dbname=aquatech_DB', $db_user, $db_pass); 
$query = $mysql->prepare("SELECT genotyped.fishid, genotyped.assayid, genotyped.allele1, genotyped.allele2, fishId.sex, " . 
"fishId.role FROM `fishId` INNER JOIN genotyped ON genotyped.fishid=fishId.catId WHERE fishId.projectid=:project"); 
$query->bindParam(':project', $project, PDO::PARAM_INT); 
$query->execute(); 

AT allele2

14_1_1 1 allele1하는 방법입니다 . 필요한 파일을 만들기 위해 두 테이블의 정보를 결합합니다.

if(!$query){ 
    $error = $query->errorInfo(); 
    print_r($error); 
} else { 
    $data = array(); 
    $rows = array(); 
    if($results = $query->fetchAll()){ 
     foreach($results as $row) 
     { 
      $rows[] = $row[0]; 
      $role[$row[0]] = $row[5]; 
      $data[$row[0]][$row[1]]['alelleY'] = $row[2]; 
      $data[$row[0]][$row[1]]['alelleX'] = $row[3]; 
     } 
     $rows = array_unique($rows); 
     foreach($rows as $ids) 
     { 
      $col2 = $role[$ids]; 
      $alelleX = $alelleY = $content = ""; 
      foreach($snp as $loci) 
      { 
       $alelleY = convertAllele($data[$ids][$loci]['alelleY']); 
       $alelleX = convertAllele($data[$ids][$loci]['alelleX']); 
       $content .= "$alelleY\t$alelleX\t"; 
      } 
      $body .= "$ids\t$col2\t" . substr($content, 0, -1) . "\n"; 

이 데이터를 구문 분석합니다. 내가 필요로하는 파일에는 개인 당 96 행보다 개인 당 하나의 행이 있어야하는데, 그 이유는 데이터를 형식화해야하기 때문입니다. 스크립트가 끝나면 $ body를 파일에 씁니다.

나는) (2

14_1_1 ATAA

$location = "results/" . "$filename" . "_result.txt"; 
$fh = fopen("$location", 'w') or die ("Could not create destination file"); 
if(fwrite($fh, $body)) 
+3

'$ results = $ query-> fetchAll()) {'을 사용하지 말고 한 번에 한 행을 가져 와서 처리하면 메모리의 $ 결과 크기가 줄어든다. –

+0

나는 가지고있다. 모든 작업으로 파일에 쓰지 않을 때 최상의 성능을 얻을 수 있음을 발견했습니다. 데이터의 길이에 따라 종종 100-1000 행마다 쓰기 작업을 수행합니다. 귀하의 경우, 메모리가 부족하거나 행이 매우 길면 모든 쓰기 작업에 대해 100 개의 레코드를 읽으십니까? (파일을 만지는 것은 정상적으로 데이터를 읽는 것과 비교하면 상당히 길다). – Fluffeh

+0

고마워, 마크. 나는 그것을 시도 할 것이다. – anotherlife

답변

4

대신 fetchAll의 변수로 데이터베이스 쿼리에서 전체 결과를 읽는

FishId 분석 한 분석으로 출력 파일이 필요합니다 행별로 행을 가져옵니다.

while($row = $query->fetch()) { ... } 
2
  1. fetchAll()은 한 번에 전체 결과를 가져 오는데, 이는 그 용도가 있지만 메모리가있어 욕심입니다. 한 번에 한 행을 처리하는 fetch()을 사용하지 않는 이유는 무엇입니까?

  2. 첫 번째 열을 기준으로 행을 인덱싱하고 다른 큰 배열을 만든 다음 중복 항목을 제거하는 것처럼 보입니다. 쿼리에 SELECT DISTINCT을 사용하여 중복되기 전에 PHP를 사용하지 않는 이유는 무엇입니까? fetch()fetchAll()보다 속도가 느려질 수 있습니다 - -

나는 충격이 속도에 어떻게 될지 모르겠어요하지만 당신은 몇 가지 처리를 저장하는 배열에서 중복을 제거 할 필요가 없습니다.

두 번째 foreach이 무엇을하는지 잘 모르겠지만 한 번에 모두이 작업을 수행 할 수 있어야합니다. 나는. fetch 루프 내의 루프는 foreach입니다. 위의 코드에

다른 관찰 :

  • $role 배열 $rows와 같은 색인 작업을 할 것 같다 - 키가 효과적으로 단일 패스에서 중복 제거로 $row[0]를 사용.SELECT DISTINCT에 의해 복제물을 제거하는 것이 더 좋을 수도 있지만 그렇지 않다면 $rows 배열과 array_unique 함수가 필요합니까?
  • 동일한 값인 $row[0]의 값이 $row[5] 인 경우 색인 생성 방법으로 데이터가 삭제되지만 데이터에있는 내용을 알고 있으므로 이미 생각한 것 같습니다 ($data 배열)
+0

안녕하세요. 스티브, 나는 물고기 ID로 색인 된 각 행에 모든 개인에 대한 96 데이터 포인트 중 하나가 포함되어 있기 때문에 DISTINCT를 선택할 수 없습니다. 그래서 나는 그것들 모두를 필요로하지만 출력 파일에서 96 포인트를 모두 한 줄로 필요로합니다. 그래서 array_unique를 사용했습니다. 그래서 개인 목록을 얻은 다음 96 행 대신 하나의 행에 표시되는 96 개의 데이터 요소를 가질 수 있습니다. 나는 그것이 의미가 있기를 바랍니다. 귀하의 답변에 감사드립니다. – anotherlife

+0

그런 경우 fetch는 fetchAll보다 메모리 집약이 적습니다. –

+0

행을 살펴볼 때 개별 ID와 데이터 포인트에 의해 색인 된 배열에 추가하십시오 (예 : $ array [$ individualid] [$ datapoint] –

관련 문제