perl - 使用mysql - 内存不足

时间:2013-09-29 06:22:22

标签: mysql perl

我正在尝试用perl做一件简单的事情,但我很难做到。我必须从mysql读取数据,然后对数据进行打印。问题是我的数据库文件的大小只有90MB,我的系统有4GB的内存。任何人都可以帮我解决这个问题吗?我的意思是为什么?

这是我的代码:

#!/usr/bin/env perl
use common::sense;
use File::Slurp;
use Text::SpeedyFx;
use DBI;
use DBD::mysql;
my $dbh = DBI->connect('dbi:mysql:enron','x','y') or die "Connection Error:     $DBI::errstr\n";

# Create cascades
my $sql = "select uniqueid,mid,sender,receiver,unixdate,body,seen from     filteredmessage";
my $sth = $dbh->prepare($sql);
$sth->execute or die "SQL Error: $DBI::errstr\n";

# Variables
my $row; 
my $uniqueId;
my $msg1;
my $sender;
my $receiver;
my $unixdate;

my $uniqueId2;
my $msg2;
my $sender2;
my $receiver2;
my $unixdate2;
my $dif;
my $row2;
my $sql2;
my $sth2;
my $j;

my $i=1;
while ($row = $sth->fetchrow_hashref) {
    my $flagSingleRow = 0;
    $uniqueId = $row->{'uniqueid'};
    $msg1 = $row->{'body'};
    $sender = $row->{'sender'};
    $receiver = $row->{'receiver'};
    $unixdate = $row->{'unixdate'};

    $sql2 = "select uniqueid,mid,sender,receiver,unixdate,body,seen from filteredmessage";
    $sth2 = $dbh->prepare($sql2);
    $sth2->execute or die "SQL Error: $DBI::errstr\n";

    $j=1;
    while ($row2 = $sth2->fetchrow_hashref) {
        $uniqueId2 = $row2->{'uniqueid'};
        $msg2 = $row2->{'body'};
        $sender2 = $row2->{'sender'};
        $receiver2 = $row2->{'receiver'};
        $unixdate2 = $row2->{'unixdate'};

        $dif = cosine_similarity($sfx->hash_fv($msg1, 8192),$sfx->hash_fv($msg2, 8192));
        #if($dif>0.5){
            print $i." ".$j." ". $dif."\n";
        #}
        $j++;
    }
    $i++;
} 

sub cosine_similarity {
    my ($a, $b) = @_;

    my $nbits_a = unpack(q(%32b*) => $a);
    my $nbits_b = unpack(q(%32b*) => $b);

    return $nbits_a * $nbits_b
        ? unpack(q(%32b*) => $a & $b) / sqrt $nbits_a * $nbits_b
        : 0;
}

4 个答案:

答案 0 :(得分:2)

Text :: SpeedyFx严重泄漏内存。这里有一个简单的演示,说明同样的东西如何导致内存增长。

#! /usr/bin/perl

use v5.12;
use strict;
use warnings;

use Text::SpeedyFx;

my $sfx = Text::SpeedyFx->new;

for(1..1_000) {
    $sfx->hash_fv("12345", 8192);
}

say `ps auwx $$`;

for(1..10_000) {
    $sfx->hash_fv("12345", 8192);
}

say `ps auwx $$`;

for(1..100_000) {
    $sfx->hash_fv("12345", 8192);
}

say `ps auwx $$`;

for(1..1_000_000) {
    $sfx->hash_fv("12345", 8192);
}

say `ps auwx $$`;

$ perl ~/tmp/test.plx
USER      PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
schwern 81574  29.1  0.1  2463756   8412 s000  S+    1:58AM   0:00.21 perl /Users/schwern/tmp/test.plx

USER      PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
schwern 81574  54.4  0.2  2463756  18000 s000  S+    1:58AM   0:00.22 perl /Users/schwern/tmp/test.plx

USER      PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
schwern 81574  70.2  1.4  2553868 118384 s000  S+    1:58AM   0:00.35 perl /Users/schwern/tmp/test.plx

USER      PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
schwern 81574  98.5 13.4  3561496 1122320 s000  S+    1:58AM   0:01.49 perl /Users/schwern/tmp/test.plx

每次调用hash_v大约1K。由于1K是位向量大小,它表示SpeedyFx分别存储对hash_v的每个调用,而不是为相同的八位字节重用相同的时隙。

我有reported this as a bug。同时,为了缓解这个问题,你可以初始化外部循环中的Text :: SpeedyFx对象。

答案 1 :(得分:1)

在重新使用$sth2->finish新查询之前,请尝试调用$sth2。 (例如,

    }
    $sth2->finish;
    $i++;
}

我的第二个评论是你的函数cosine_similarity是对称的(即cosine_similarity(x,y) = cosine_similarity(y,x))。因此,如果您向ORDER BY uniqueid添加$sql并对$sql2进行适当更改,只能获取uniqueid >= $uniqueId的行,则可以减少近50%的时间。

答案 2 :(得分:0)

是否可以在语句句柄上使用'fetchrow_arrayref'而不是'fetchrow_hashref'?然后,您必须使用特定的数组索引而不是散列键来获取值。

while ($row = $sth->fetchrow_arrayref) {
    my $flagSingleRow = 0;
    $uniqueId = $row->[0];
    $msg1 = $row->[1];
    $sender = $row->[2];
    $receiver = $row->[3];
    $unixdate = $row->[4];
...
# and similarly for $sth2

数组中每个字段的实际位置取决于select语句中列的顺序。 试一试,让我们知道结果。

答案 3 :(得分:0)

似乎我的程序的主要问题是使用$ sfx-> hash_fv。我必须提出一些改进这一功能的想法。这不是我自己的功能,它来自SpeedyFx包。无论如何,谢谢你们。