2008-10-17 21 views
5

Tôi có mã tìm kiếm một cái gì đó như thế này:Làm thế nào để xây dựng lớn truy vấn MySQL INSERT trong PHP mà không lãng phí bộ nhớ

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

Tôi biết điều này không phải là rất hiệu quả như từng '' các toán tử sẽ tái phân bổ một khối bộ nhớ lớn hơn và chuỗi 30MB sẽ được sao chép nhiều lần.

Có điều gì hiệu quả hơn giải pháp sau không?

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

Trả lời

7

Bạn có hai vấn đề ở đây:

# 1, có nhiều cách khác nhau bạn có thể tính toán băm MD5:

  • Hãy làm như bạn làm và nạp vào PHP như là một chuỗi và sử dụng PHP md5()
  • sử dụng PHP md5_file()
  • Tính đến PHP 5.1 trở lên, bạn có thể sử dụng dòng API của PHP với một trong hai md5 hoặc md5_file để tránh nạp hoàn toàn vào bộ nhớ
  • 012.
  • Sử dụng exec() để gọi lệnh của hệ thống md5sum
  • MD5() chức năng
  • Sử dụng MySQL để tính toán hash

Kể từ đây là tất cả tầm thường để thực hiện nó sẽ dễ dàng cho bạn để thực hiện và chuẩn tất cả chúng để sử dụng bộ nhớ và tốc độ. Dưới đây là some benchmarks hiển thị hệ thống md5 qua exec nhanh hơn rất nhiều so với kích thước tệp md5_file của PHP khi kích thước tệp tăng lên. Làm theo cách của bạn chắc chắn là cách tồi tệ nhất khi sử dụng bộ nhớ có liên quan.

# 2, mysql_real_escape_string thực hiện truy vấn cơ sở dữ liệu, vì vậy bạn thực sự đang truyền dữ liệu blob của mình tới cơ sở dữ liệu, lấy lại chuỗi đó và truyền lại (!) Bằng truy vấn INSERT. Vì vậy, nó đi du lịch đến/từ máy chủ DB 3x thay vì 1x và sử dụng 2x bộ nhớ trong PHP.

Sẽ hiệu quả hơn khi sử dụng PHP5 prepared statements và chỉ gửi dữ liệu này đến cơ sở dữ liệu một lần. Đọc phần bài viết liên kết, bạn sẽ thấy nó đề cập rằng khi bạn đang ràng buộc các tham số, bạn có thể sử dụng kiểu blob để truyền dữ liệu blob đến DB theo khối. Các PHP docs for mysqli_stmt::send_long_data có một ví dụ đơn giản tuyệt vời này INSERTs một tập tin vào một cột blob giống như bạn đang có.

Bằng cách đó, và bằng cách sử dụng API luồng, md5_file hoặc exec với lệnh md5 hệ thống, bạn có thể thực hiện toàn bộ INSERT mà không cần tải toàn bộ tệp vào bộ nhớ, có nghĩa là sử dụng bộ nhớ cho chuỗi hoạt động của bạn thấp như bạn muốn!

0

Bạn đã đánh giá được thủ thuật đệm đầu ra chưa?

ob_start(); 
echo 'INSERT INTO some_table SET BlobData = \'', mysql_real_escape_string($data), '\', BlobHash = \'', $hash, '\''; 
mysql_query(ob_get_clean()); 

Một điều khác bạn có thể làm là chuyển sang mysqli hoặc MDB2, hỗ trợ các tham số ràng buộc. Điều đó sẽ cho phép bạn bỏ qua các kết nối chuỗi mysql_real_escape_string .

-1

Nếu sử dụng bộ nhớ là vấn đề của bạn, bạn có thể đọc tệp lớn theo khối và chèn các đoạn này bằng CONCAT vào trường cơ sở dữ liệu.

Mẫu mã (không kiểm tra):

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

Phương pháp này sẽ chậm hơn nhưng bạn sẽ chỉ cần 4KB bộ nhớ của bạn.

3

Nếu bạn đang sử dụng PDO và các số liệu đã chuẩn bị, bạn có thể sử dụng loại PDO :: PARAM_LOB. Xem ví dụ # 2 trên trang LOB cho biết cách chèn hình ảnh vào cơ sở dữ liệu bằng cách sử dụng con trỏ tập tin.

http://us2.php.net/manual/en/pdo.lobs.php

+0

Vấn đề với PDO là nó chỉ mô phỏng các câu lệnh đã chuẩn bị nếu bạn không có thư viện mysqli. Vì vậy, tất cả điều này làm là di chuyển các concatenate vào thư viện PDO. – jmucchiello

0

Nó sẽ thực hiện bất kỳ sự khác biệt nếu bạn không đặt truy vấn vào một biến khác, nhưng thay vì thông qua nó trực tiếp vào lệnh MySQL. Tôi chưa bao giờ thử điều này, nhưng nó có thể tạo sự khác biệt vì toàn bộ chuỗi không được lưu trữ trong một biến khác.

Các vấn đề liên quan