1. 程式人生 > >對比PHP對MySQL的緩衝查詢和無緩衝查詢

對比PHP對MySQL的緩衝查詢和無緩衝查詢

關於緩衝查詢和無緩衝查詢 MySQL的客戶端有兩種型別的查詢:緩衝查詢:將接收查詢的結果並把他們儲存在客戶端的快取中,而且接下來獲取行記錄的請求僅僅從本地內獲取。 (1)優點:可以在結果集中自由地移動“當前行”的指標,這樣很容易找到,因為結果是存在客戶端的。 (2)缺點:需要額外的記憶體來儲存這些結果集,而且需要大量的記憶體,另外,php中用來執行查詢的函式會一直到所有的結果都接收才會返回值。

無緩衝查詢:會限制你通過嚴格的順序訪問查詢結果。但他不需要額外的記憶體來儲存整個結果集。你可以在MySQL伺服器開始返回值的時候就開始獲取而處理或顯示資料行。當使用無緩衝結果集時,必須使用mysql_fetch_row函式獲取所以的資料行,或者在給伺服器傳送其他任何命令前用mysql_free_result函式關閉結果集。

哪種型別的查詢好?最好的根據是具體情況而定,無緩衝查詢在結果集巨大的時為你節省大量的臨時記憶體,而且查詢不需要排序時,php在MySQL資料庫實際上還在處理時就可以獲得第一個資料行。 快取查詢便於尋找,它可以提供一個全面的尋找加速。因為每一個單獨的查詢的都會快讀結束,mysql快速的獲取結果集並存放在記憶體中,而不是在處理PHP程式碼時保持查詢為可用的。 另外一個無緩衝查詢的限制是在所有的資料行都被讀取或者結果集用mysqli_free_result釋放之前,你將無法向伺服器傳送任何命令。

PHP+MySQL緩衝查詢和無緩衝查詢 PHP MySQL查詢(mysqli,pdo_mysql)預設使用緩衝模式.  也就是說查詢結果將一次性從MySQL傳輸到PHP程序記憶體中,  這時可以統計結果集的行數,以及移動結果集指標.  緩衝模式下,如果結果集很大,那麼PHP程序也會佔用大量的記憶體,  直到結果集被unset或者free.

store_result用於緩衝模式,所有結果一次性儲存到PHP程序中: 

1

2

3

mysqli::query MYSQLI_STORE_RESULT

mysqli::store_result

mysqli_stmt::store_result

如果PHP的MySQL資料庫驅動底層用的是libmysqlclient,那麼memory_limit不能統計到結果集佔用的記憶體,  除非結果集已經賦值給PHP變數,如果底層使用mysqlnd作為驅動時則可以統計到(PHP從5.4開始底層預設使用mysqlnd).  無緩衝模式下執行的查詢將會返回一個resource資源引用,位於MySQL的查詢結果等待PHP獲取.  無緩衝模式下,PHP程序佔用的記憶體很少,但會增大MySQL伺服器的負載.  在PHP取回所有結果前,在當前資料庫連線下不能傳送其他的查詢請求.

use_result表示無緩衝查詢: 

1

2

mysqli::query MYSQLI_USE_RESULT

mysqli::use_result

總結:  當結果集不大時,或者需要在讀取所有行前獲取結果集行數時,使用緩衝查詢(預設).  當結果集很大時,使用無緩衝查詢,避免PHP程序佔用大量的記憶體. 

1

2

3

$rs = $mysqli->query("SELECT * FROM City", MYSQLI_USE_RESULT);

$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);

$rs = $pdo->query("SELECT * FROM City");

預設情況下,mysqli_stmt的SELECT查詢結果將留在MySQL伺服器上,等待fetch方法把記錄逐條取回到PHP程式中,這樣做會降低效能,但能節省記憶體.  如果需要對所有記錄進行處理,可以呼叫mysqli_stmt::store_result,把所有結果一次性全部傳回到PHP程式中,  這樣做更高效,能減輕MySQL伺服器的負擔,雖然記憶體佔用會多一些.  如果獲取SELECT語句查詢到了多少條記錄,可以用 mysqli_stmt::$num_rows 獲取.  這個屬性只有在提前執行過 mysqli_stmt::store_result 方法,將全部查詢結果傳回到PHP程式中的情況下才可以使用.  對比 mysqli_result::$num_rows 則不沒有這個限制.  用 mysqli_stmt::free_result 關閉 mysqli_stmt::store_result: 

1

2

3

$stmt->store_result();

echo $stmt->num_rows;

$stmt->free_result();

mysqli_stmt::store_result能讓mysqli_stmt::fetch更高效,但也需要用mysqli_stmt::free_result顯式關閉.  可以用mysqli_stmt::get_result拿到結果集物件$result,然後mysqli_result::fetch_all拿到查詢陣列$results: 

1

2

$result = $stmt->get_result();

$results = $result->fetch_all(MYSQLI_ASSOC);

整理一下相關引數:

1

2

3

4

5

6

7

8

9

10

11

mysqli::query//執行SQL,成功返回mysqli_result(SELECT,SHOW,DESCRIBE操作)物件或TRUE(其他操作),失敗返回FALSE.用mysqli::close關閉.

mysqli::prepare//預處理SQL,成功返回statement物件,失敗返回FALSE.

mysqli_stmt::execute//執行SQL.用mysqli_stmt::close關閉.

mysqli_stmt::store_result//取回全部查詢結果(SELECT,SHOW,DESCRIBE,EXPLAIN)到PHP,可選.用mysqli_stmt::free_result關閉.

mysqli_stmt::bind_result//把prepare和execute產生的結構繫結結果到變數,然後在mysqli_stmt::fetch中把這些變數輸出或賦值.

mysqli_stmt::fetch//每次返回結果集的一條,賦值給mysqli_stmt::bind_result繫結的變數.

mysqli_stmt::get_result//獲得結果物件,然後呼叫mysqli_result::fetch_all就能返回結果集陣列.mysqlnd下可用.

mysqli_result::fetch_all//返回一個結果集陣列(MYSQLI_NUM(預設),MYSQLI_ASSOC,MYSQLI_BOTH),用mysqli_result::close關閉.mysqlnd下可用.

mysqli_result::fetch_array//每次返回結果集的一條,包含一個一維的數字陣列和關聯陣列.

mysqli_result::fetch_assoc//每次返回結果集的一條,即一個一維的關聯陣列.

mysqli_result::fetch_row//每次返回結果集的一條,即一個一維的數字陣列.