从内存有限的mysql处理大型结果集

时间:2014-05-22 11:05:34

标签: php mysql performance memory pdo

我有一个大型数据库,其中包含1500个人的实验结果。每个人有96个数据点。我编写了以下脚本来总结然后格式化数据,以便分析软件可以使用它。起初一切都很好,直到我有500多人。现在我的内存不足了。

我想知道现在是否有人建议在不牺牲速度的情况下克服内存限制问题。

这是表格在数据库中的外观

fishId assayId allele1 allele2

14_1_1 1 A T

14_1_1 2 A A

$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();  

所以这是对数据库的调用。它正在连接两个表中的信息以构建我需要的文件。

 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写入文件。

我需要输出文件

FishId Assay 1 Assay 2

14_1_1 A T A A

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

2 个答案:

答案 0 :(得分:4)

不是使用fetchAll()将数据库查询的整个结果读入变量,而是逐行获取它:

while($row = $query->fetch()) { ... }

答案 1 :(得分:2)

  1. fetchAll()一次性获取整个结果,它有其用途但对内存贪婪。为什么不使用一次处理一行的fetch()

  2. 您似乎按第一列索引行,创建另一个大型数组,然后删除重复项。为什么不在查询中使用SELECT DISTINCT来删除重复项到PHP之前?

  3. 我不确定对速度的影响是什么 - fetch()可能比fetchAll()慢 - 但是您不必从阵列中删除重复项,这可以节省一些处理

    我也不确定你的第二个foreach正在做什么,但你应该能够一次完成所有这一切。即在获取循环中的foreach循环。

    上述代码的其他观察结果:

    • $role数组似乎与$rows执行相同的索引编制工作 - 使用$row[0]作为键有效地删除单个传递中的重复项。通过SELECT DISTINCT删除重复项可能更好,但如果没有,您是否需要$rows数组和array_unique函数?
    • 如果$row[0]的相同值可以具有不同的$row[5]值,那么您的索引方法将丢弃数据 - 但您知道数据中的内容是什么,所以我猜你是'已经想到了这一点($data数组也是如此)