我的代码看起来像这样:
$data = file_get_contents($tempFile); // perhaps 30MB of file data, now in PHP's memory
$hash = md5($data);
$query = "INSERT INTO some_table
SET BlobData = '" . mysql_real_escape_string($data) . "',
BlobHash = '$hash'
";
mysql_query($query);
我知道每个''都不是很有效率。运算符将重新分配更大的内存块,并且将多次复制30MB字符串。
有没有比以下解决方案更有效的方法?
$data = file_get_contents($tempFile); // perhaps 30MB of file data, now in PHP's memory
$hash = md5($data);
$query = "INSERT INTO some_table SET BlobData = '%s', BlobHash = '$hash'";
mysql_query(sprintf($query, mysql_real_escape_string($data)));
答案 0 :(得分:7)
这里有两个问题:
#1,有几种不同的方法可以计算MD5哈希值:
md5()
md5_file()
md5
或md5_file
一起使用,以避免完全加载到内存中exec()
来调用系统的md5sum
命令MD5()
函数计算哈希值由于这些都很容易实现,因此您可以轻松地实现所有内存使用和速度并对其进行基准测试。以下some benchmarks显示系统md5通过exec
比PHP的md5_file
快得多,因为文件大小增加。就内存使用而言,按照自己的方式行事绝对是最糟糕的方式。
#2,mysql_real_escape_string
执行数据库查询,因此您实际上将blob数据传输到数据库,将其作为字符串返回,然后使用INSERT查询再次传输(!)。所以它往返于DB服务器3x而不是1x,并且在PHP中使用2x内存。
使用PHP5 prepared statements会更高效,并且只将此数据发送到数据库一次。阅读链接的文章部分,您将看到它提到在绑定参数时,您可以使用blob类型将blob数据以块的形式传输到数据库。 PHP docs for mysqli_stmt::send_long_data
有一个非常简单的例子,就像你一样将文件插入到blob列中。
通过这样做,并使用系统md5命令使用流API,md5_file
或exec
,您可以完成整个INSERT,而无需将整个文件加载到内存中,这意味着内存您的一系列操作的用法可以尽可能低!
答案 1 :(得分:3)
如果您正在使用PDO和准备好的语句,则可以使用PDO :: PARAM_LOB类型。请参阅LOB页面上的示例#2,其中显示了如何使用文件指针将图像插入数据库。
答案 2 :(得分:0)
您是否对输出缓冲技巧进行了基准测试?
ob_start();
echo 'INSERT INTO some_table SET BlobData = \'', mysql_real_escape_string( $data ), '\', BlobHash = \'', $hash, '\'';
mysql_query( ob_get_clean() );
您可以做的另一件事是转换为支持绑定参数的mysqli或MDB2。这将允许您跳过mysql_real_escape_string调用和字符串连接。
答案 3 :(得分:0)
如果您没有将查询放入另一个变量,而是将其直接传递给MySQL命令,它会有什么不同吗?我从来没有试过这个,但它可能会有所不同,因为整个字符串没有存储在另一个变量中。
答案 4 :(得分:-1)
如果内存使用是您的问题,您可以读取块中的大文件,并将这些块与CONCAT一起插入数据库字段。
示例代码(未经测试):
$id = 1337;
$h = fopen("path/to/file.ext", "r");
while (!feof($h))
{
$buffer = fread($h, 4096);
$sql = "UPDATE table SET my_field = CONCAT(my_field, '" . mysql_real_escape_string($buffer) . "') WHERE Id = " . $id;
mysql_query($sql);
}
这种方法会慢一些,但你只需要4Kb的内存。