2010-04-01 62 views
12

我聽說有一種傳聞,當把二進制數據(文件等)插入到MySQL中時,應該使用bin2hex()函數並將其作爲HEX編碼值發送,而不是僅僅使用mysql_real_escape_string二進制字符串並使用它。爲什麼在將二進制數據從PHP插入MySQL時使用bin2hex?

// That you should do 
$hex = bin2hex($raw_bin); 
$sql = "INSERT INTO `table`(`file`) VALUES (X'{$hex}')"; 

// Rather than 
$bin = mysql_real_escape_string($raw_bin); 
$sql = "INSERT INTO `table`(`file`) VALUES ('{$bin}')"; 

它被認爲是出於性能原因。與MySQL如何處理大字符串有關,以及如何處理HEX編碼的值

但是,我很難確認這一點。我所有的測試都顯示了確切的對立面; bin2hex方法慢了85%,並且使用了大約24%的內存。
(我在PHP 5.3中,MySQL 5.1測試此,Win7的X64 - 使用farily簡單的插入環)

例如,該圖顯示了的mysqld進程的私有內存使用,同時測試代碼正在運行:

Private Bytes used by the mysqld process http://atli.advefir.com/images/priv_mem_cropped.gif

有誰知道,澄清這個任何解釋相關或reasources?

謝謝。

+0

有可能當你用'「INSERT INTO \'表\'(\'文件\')VALUES(X {有差別的性能$ hex})「;'(從十六進制值中刪除引號)? (+1 btw) – Jacco 2010-04-02 10:47:33

+0

@Jacco感謝您的建議。我做了一些測試,兩種方法看起來幾乎完全相同。儘管'X'...''方法在內存和CPU使用率方面似乎都略有優勢。 - 我一起編輯了結果並上傳了它們,以防你感興趣:http://atli.advefir.com/images/myisam_joined.png,http://atli.advefir.com/images/innodb_joined.png – Atli 2010-04-02 15:01:07

+0

有趣的,我真的很想讓DBA在這裏解釋'爲什麼'。 – Jacco 2010-04-02 16:04:45

回答

9

這聽起來像一個都市傳說給我。

bin2hex()在輸入字節的每個字節映射輸出('a' - >'61'),所以你應該注意到了腳本的顯著內存增加執行查詢 - 它至少應使用盡可能多的內存更多作爲要插入的二進制數據的字節長度。

此外,這意味着,在一個長的字符串運行bin2hex()需要長於運行mysql_real_escape string(),其中 - 在MySQL's documentation解釋 - 只是逸出6個字符:NULL\r\n\,和「控制-Z 」。

這是PHP部分,現在是MySQL:服務器需要執行反向操作才能正確存儲數據。任何一個函數的倒置幾乎與原始操作一樣長 - mysql_real_escape_string()的反向函數需要用未轉義的值()替換未轉義的值(\),而bin2hex()的反轉將需要替換每個和每個字節元組用一個新的字節。

由於二進制數據調用mysql_real_escape_string()是安全的(根據MySQL的和PHP's documentation或者即使只是考慮到操作不會做任何其他的轉換比上面列出的),它將使絕對沒有任何意義執行這樣的昂貴操作。例如如果遇到類似的問題,因爲這裏所描述

+0

這很有道理。單獨在PHP中存儲查詢字符串所需的額外內存似乎足以避免'bin2hex'函數的原因,而我自己的測試表明MySQL也受到影響。然後是轉換的額外CPU成本。 - 這聽起來越來越像城市傳奇。不過,我不得不想知道這是什麼開始的,爲什麼人們認爲這是一個好主意。 – Atli 2010-04-11 13:24:28

+0

我想有些人認爲用一個名爲'..._ escape_string'的函數對二進制數據進行編碼或在可讀的SQL語句中發送二進制數據可能不明智,但實際上並沒有什麼錯(儘管可能已經是函數的別名 - 比如'mysql_escape_data()'或類似的) – soulmerge 2010-04-11 20:22:32

+0

好點。我可以看到人們如何看待它,尤其是那些來自強類型語言的人。 - 儘管如此,我從來沒有真正考慮過他們。我的意思是,PHP字符串基本上就是字節數組,就像二進制數據一樣。 (至少在PHP 6之前) – Atli 2010-04-12 06:33:33

4

十六進制字符串比相應的二進制字符串長得多。只需傳輸時間並將其複製到PHP和MySQL的內存中即可。

在所有誠實中,我不是底層實現方面的專家,但不是在SQL內傳遞數據更好,但使用例如PDOStatement的參數綁定?也許有人更熟悉這裏可以確認這是否確實會導致數據作爲二進制字符串發送,完全不在SQL語句之外,或者PDO是否在轉換引擎下進行轉義和查詢字符串操作。

無論哪種方式,您都可以獲得安全(簡單)的好處。

+0

感謝您的回覆。儘管這也是我的第一次;轉換過程和字符串的添加長度會導致性能下降。看來我們是正確的。 - 但是,我現在發現了幾個頁面,顯示了使用'bin2hex'函數(甚至更令人不安的是,Base64函數),並且我看不出原因。這是沒有道理的 - 順便說一句,我個人使用準備好的語句(通常是mysqli)。這個問題是比實際更假設的:) – Atli 2010-04-01 08:13:09

+0

bin2hex/base64將避免任何字符集問題,如果表(錯誤地)用TEXT字段而不是BLOB創建的話。但是以數據大小增加3倍爲代價(假設數據完全不是ascii並完全轉換爲%xx%yy%zz ...) – 2010-04-01 14:29:41

+0

十六進制和base64都會增加數據發送的大小。十六進制數據以二進制形式存儲。稍後,數據以base64編碼格式存儲,因此大33%。 (但是這不回答OP的問題) – Jacco 2010-04-02 10:51:32

5

我一直在測試這個我自己,我想出了相當一致的結果。 (雖然我的測試是一點點粗糙的。)

我已經測試過電腦

  1. 的Windows 7(64位),PHP 5.3,MySQL 5.1中
  2. Ubuntu 9.10的(x64)的PHP 5.2中,MySQL 5.1
  3. 的Ubuntu 10.04(X32)PHP 5.3,MySQL 5.1中

到目前爲止,在所有三個平臺的測試表明相同的吊環:

  • 在MyISAM上插入BLOB比在InnoDB上快2到8倍。二進制字符串的差異似乎比HEX編碼的字符串要高。(參見下面的數據)
  • 使用HEX編碼字符串bin2hexX'...'使用更多的內存,平均來說,比使用轉義二進制字符串mysql_real_escape_string對原始數據)。 - 這對於MyISAM和InnoDB都是如此。
  • MyISAM上的二進制字符串更快,但InnoDB上的HEX編碼數據更快。

試驗基本上只是一個簡單的循環逃脫或十六進制編碼的原始數據(在腳本的頂部檢索一次2.4 MIB圖像),構造查詢字符串,並執行它通過mysql_querymysqli::query函數。 - 我測試了兩個擴展。似乎沒有任何區別。

我將Ubuntu 10.04(#3)的結果放在電子表格中。從Ubuntu 9.10(#2)機器的結果幾乎是相同的,所以我沒有打擾它們進行設置:(!最後的藉口正確測試的谷歌文檔的東西XD)

這些圖顯示Win7(#1)機器上的mysqld進程的私有內存使用情況。

相關問題