我有一个由字符串和数字概率组成的数据库(还有其他列,但它们与问题无关)。简化的架构是
+-----------------------+----------------------+
| 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 运行 mysql Ver 14.14 Distrib 5.1.41,适用于 debian-linux-gnu (x86_64)。
最佳答案
该表的主键是什么样的?如果您使用整数代理键,您可以:[假设 4 字节整数]
- 转储所有键的列表。
$list[]
[240MB 给予或接受] - 复制列表。
$shuf[]
[另外 240MB +/-] - 打乱重复列表。 [shuffle 函数可能会返回一个副本,在这种情况下跳过 #2]
- 向表中添加另一列[即:
shuffle_key
],暂时没有索引。 我不太熟悉 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); }
在新列上创建 UNIQUE 索引。
现在,您可以在主键和混洗键上自连接表,并使用一侧的 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 列上,这样您就不会在操作过程中收到重复的键警告。之后重新添加索引。
关于mysql - 如何随机化单个 mysql 列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14485636/