我正在嘗試回傳將 3 個表連接在一起以供用戶下載為 CSV 的結果,這會引發錯誤:
允許的記憶體大小為 734003200 位元組已用盡
這是正在運行的查詢:
SELECT *
FROM `tblProgram`
JOIN `tblPlots` ON `tblPlots`.`programID`=`tblProgram`.`pkProgramID`
JOIN `tblTrees` ON `tblTrees`.`treePlotID`=`tblPlots`.`id`
導致錯誤的代碼行是這樣的:
$resultsALL=$this->db->query($fullQry);
其中 $fullQry 是上面顯示的查詢。當我注釋掉那一行時,一切運行都沒有錯誤。所以我確定它不是我錯過的某個地方的無限回圈。
我想知道如何分解查詢,以便在不出錯的情況下獲得結果?這些表現在只有相對少量的資料,最終會更大,所以我認為提高記憶體大小不是一個好的選擇。
我正在使用 CodeIgniter/php/mysql。如果需要,我可以提供更多代碼...
感謝您提供任何建議!
uj5u.com熱心網友回復:
基于:MySQL:按塊檢索大選擇
您也可以嘗試使用該LIMIT子句以塊的形式檢索資料。
由于您使用的是 CodeIgniter 3,因此您可以這樣做。
如果您的聯接表具有沖突的列名,您可能需要將不同的$orderBy 引數#6傳遞給該方法。getChunk(...)id
IE:$this->getChunk(..., ..., ..., 0, 2000, "tblProgram.id");
解決方案:
<?php
class Csv_model extends CI_Model
{
public function __construct()
{
parent::__construct();
$this->load->database();
}
public function index()
{
$sql = <<< END
SELECT *
FROM `tblProgram`
JOIN `tblPlots` ON `tblPlots`.`programID`=`tblProgram`.`pkProgramID`
JOIN `tblTrees` ON `tblTrees`.`treePlotID`=`tblPlots`.`id`
END;
$this->getChunk(function (array $chunk) {
/*
* Do something with each chunk here;
* Do something with each chunk here;
* log_message('error', json_encode($chunk));
* */
}, $this->db, $sql);
}
/*
* Processes a raw SQL query result in chunks sending each chunk to the provided callback function.
* */
function getChunk(callable $callback, $DBContext, string $rawSQL = "SELECT 1", int $initialRowOffset = 0, int $maxRows = 2000, string $orderBy = "id")
{
$DBContext->query('DROP TEMPORARY TABLE IF EXISTS chunkable');
$DBContext->query("CREATE TEMPORARY TABLE chunkable AS ( $rawSQL ORDER BY `$orderBy` )");
do {
$constrainedSQL = sprintf("SELECT * FROM chunkable ORDER BY `$orderBy` LIMIT %d, %d", $initialRowOffset, $maxRows);
$queryBuilder = $DBContext->query($constrainedSQL);
$callback($queryBuilder->result_array());
$initialRowOffset = $initialRowOffset $maxRows;
} while ($queryBuilder->num_rows() === $maxRows);
}
}
uj5u.com熱心網友回復:
用于
getUnbufferedRow()處理大型結果集。
getUnbufferedRow()
此方法回傳單個結果行,而不像以前那樣將整個結果預取到記憶體
row()中。如果您的查詢不止一行,它會回傳當前行并將內部資料指標向前移動。
$query = $db->query("YOUR QUERY");
while ($row = $query->getUnbufferedRow()) {
echo $row->title;
echo $row->name;
echo $row->body;
}
為了與 MySQLi 一起使用,您可以將 MySQLi 的結果模式設定
MYSQLI_USE_RESULT為以最大程度地節省記憶體。通常不建議使用它,但它在某些情況下可能是有益的,例如將大型查詢寫入 csv。如果您更改結果模式,請注意與之相關的權衡。
$db->resultMode = MYSQLI_USE_RESULT; // for unbuffered results
$query = $db->query("YOUR QUERY");
$file = new \CodeIgniter\Files\File(WRITEPATH.'data.csv');
$csv = $file->openFile('w');
while ($row = $query->getUnbufferedRow('array'))
{
$csv->fputcsv($row);
}
$db->resultMode = MYSQLI_STORE_RESULT; // return to default mode
筆記:
在同一連接上使用
MYSQLI_USE_RESULT所有后續呼叫將導致錯誤,直到獲取所有記錄或進行freeResult()呼叫。該getNumRows()方法將僅根據資料指標的當前位置回傳行數。MyISAM 表將保持鎖定狀態,直到獲取所有記錄或進行freeResult()呼叫。
您可以選擇傳遞“物件”(默認)或“陣列”以指定回傳值的型別:
$query->getUnbufferedRow(); // object
$query->getUnbufferedRow('object'); // object
$query->getUnbufferedRow('array'); // associative array
freeResult()
It frees the memory associated with the result and deletes the result resource ID. Normally PHP frees its memory automatically at the end of script execution. However, if you are running a lot of queries in a particular script you might want to free the result after each query result has been generated in order to cut down on memory consumption.
$query = $thisdb->query('SELECT title FROM my_table');
foreach ($query->getResult() as $row) {
echo $row->title;
}
$query->freeResult(); // The $query result object will no longer be available
$query2 = $db->query('SELECT name FROM some_table');
$row = $query2->getRow();
echo $row->name;
$query2->freeResult(); // The $query2 result object will no longer be available
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/454046.html
標籤:php sql 代码点火器 codeigniter-3
