0

我有一个由字符串和数字概率组成的数据库(还有其他列,但它们与问题无关)。一个简化的模式是

+-----------------------+----------------------+
| gopair                | P_high               |
+-----------------------+----------------------+
| GO:0000398_GO:0030540 |    0.275997567007171 |
| GO:0015198_GO:0016846 | 5.24489289777325e-06 |
| GO:0034649_GO:0072141 |  0.00338367340340417 |
| GO:0004303_GO:0031053 |    0.110417921058026 |
+-----------------------+----------------------+

在我的工作中,我运行一个脚本来查询数据库中与特定 GO 对关联的值。我需要证明我的结果与随机获得的结果不同。因此,我要运行的测试之一是对P_high列进行洗牌,然后运行我的脚本并分析结果。

我试图洗牌输入文件并重新加载数据库,但这很复杂,因为有问题的输入文件是一个 7GB 的文本文件,在只有 3GB RAM 的机器上很难处理。

那么,有没有一种方法可以随机化数据库中的特定列,同时保持其余部分保持不变?

注意事项:

  • 有问题的表很大(60,164,966 行)。
  • 我不需要严格的数学随机性
  • 我需要保持相同的频率。如果N对在真实数据库中具有P的概率,我需要N对在随机一对中具有P的概率。
  • 我需要持久的解决方案。我的脚本可以多次查询数据库中的同一对,因此仅选择随机对是不够的。
  • 我需要重复执行所有这些操作,因此首选可编写脚本(最好是 Perl)的解决方案。
  • 我在 Ubuntu 服务器上使用 readline 6.1 为 debian-linux-gnu (x86_64) 运行 mysql Ver 14.14 Distrib 5.1.41。
4

1 回答 1

1

该表的主键是什么样的?如果您使用整数代理键,您可以:[假设 4 字节整数]

  1. 转储所有键的列表。$list[][240MB 让步]
  2. 复制列表。$shuf[][另一个 240MB +/-]
  3. 随机播放重复列表。[shuffle 函数可能会返回一个副本,在这种情况下跳过 #2]
  4. 在您的表中添加另一列 [ie: shuffle_key],暂时没有索引。
  5. 我对 Perl 语法不是很熟悉,但它类似于 PHP,所以:

    $cnt = count($list);
    for($i=0; $i<$cnt; $i++) {
        $query = sprintf(
            'UPDATE table SET shuffle_key = %d WHERE primary_key = %d',
            $shuf[$i], $list[$i] );
        $dbh->doQuery($query);
    }
    
  6. 在新列上创建唯一索引。

  7. 现在您可以在主键和洗牌键上自连接表,并从一侧使用 gopair 并从另一侧使用 P_high。

    SELECT t1.gopair, t2.P_high
    FROM table t1 INNER JOIN table t2
      ON t1.primary_key = t2.shuffle_key
    

这应该需要的内存量大约是主键大小 * 行数的 2 倍,但即使在较大的一侧,我认为它占用的内存也不会超过几个 GB。

注意:每次你想洗牌你需要把索引放在 shuffle_index 列上,这样你就不会在操作中间收到重复的键警告。之后重新添加索引。

于 2013-01-23T18:34:05.550 回答