内存分配,字节已用尽 PHP/LARAVEL
Memory Allocation, Bytes Exhausted PHP/LARAVEL
大家好,
我正在使用 Laravel Excel/Maatwebsite 开发一个系统。我想要实现的是,当用户将 excel 文件插入系统时,系统将检查一些内容,然后将数据插入数据库。
这是数据库模式的一个实例:
Hadees:
h_id | h_english | r_id | h_last_raavi_id | b_id | s_id | k_id | h_status
Raavi:
r_id | r_english | r_status
Baab:
b_id | b_english | s_id | b_status
Section:
s_id | s_english | k_id | s_status
Kitaab:
k_id | k_english | k_status
我的控制器:
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\Section;
use App\Models\Raavi;
use App\Imports\HadeesImport;
use Excel;
class ImportHadeesController extends Controller{
/**
* Show the application import-hadees page.
*
* @return \Illuminate\Http\Response
*/
public function index(){
$section = Section::where(['s_status' => 1])->get();
return view('admin/import-hadees', compact('section'));
}
/**
* This method uses the Excel facade to prep the excel file
* and extract data from it and uses App\Imports\HadeesImport
* class to insert each row in the database schema accordingly.
*
* @param Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function importHadees(Request $request){
$raavi = Raavi::where(['r_status' => 1])->get();
if($request->file('hadees_sheet')) {
} else {
return response()->json(['status'=>'error', 'msg'=> 'No file present!']);
}
$temp = $request->file('hadees_sheet')->store('temp');
$path=storage_path('app').'/'.$temp;
$hadees = Excel::import(new HadeesImport($request->s_id, compact('raavi')), $path);
if($hadees){
return response()->json(['status'=>'success', 'msg'=> 'Successfully imported all the data from the file to the database!']);
} else{
return response()->json(['status'=>'error', 'msg'=> 'Unable to import data from the file to the database!']);
}
}
}
HadeesImport Class:
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use App\Models\Section;
use App\Models\Baab;
use App\Models\Hadees;
use App\Models\Raavi;
class HadeesImport implements ToCollection, WithHeadingRow{
/**
* Global variable for section_id.
*/
public $s_id;
/**
* Global variable for raavi's data.
*/
public $raavi;
/**
* Construction function.
*
* @param int $id
*/
function __construct($id, $arr) {
$this->s_id = $id;
$this->raavi = $arr;
}
/**
* This method is responsible for inserting the excel
* sheet's rows data to the database schema.
*
* @param Collection $row
*/
public function collection(Collection $rows){
$baab = Baab::where(['s_id' => $this->s_id])->get();
$hissa = Section::where(['s_id' => $this->s_id])->first();
$kitaab = $hissa->k_id;
$first_raavi = 0;
$last_raavi = 0;
$baab_id = 0;
$data = array();
foreach ($rows as $row){
if($row['hadees_arabic'] != "" && $row['hadees_urdu'] != ""){
$baab_id = $this->baabCheck($baab, $row);
foreach($this->raavi['raavi'] as $rav){
if(trim($rav->r_english) == trim($row['first_raavi_english'])){
$first_raavi = $rav->r_id;
} else{
$first_raavi = 0;
}
$last_raavi = (trim($rav->r_english) == trim($row['last_raavi_english']))? $rav->r_id : 0;
}
if($first_raavi == 0){
$raavi = Raavi::create([
'r_arabic' => trim($row['first_raavi_urdu']),
'r_urdu' => trim($row['first_raavi_urdu']),
'r_english' => trim($row['first_raavi_english']),
'r_nickname' => trim($row['raavi_other_names']),
'r_status' => 1,
]);
$first_raavi = $raavi->r_id;
}
if($last_raavi == 0){
$raavi = Raavi::create([
'r_arabic' => trim($row['last_raavi_urdu']),
'r_urdu' => trim($row['last_raavi_urdu']),
'r_english' => trim($row['last_raavi_english']),
'r_nickname' => 'n/a',
'r_status' => 1,
]);
$last_raavi = $raavi->r_id;
}
$data = array([
'h_arabic' => trim($row['hadees_arabic']),
'h_urdu' => trim($row['hadees_urdu']),
'h_english' => trim($row['hadees_english']),
'h_roman_keywords' => trim($row['roman_keywords']),
'h_number' => trim($row['hadees_number']),
'r_id' => $first_raavi,
'h_last_raavi_id' => $last_raavi,
'b_id' => $baab_id,
's_id' => $this->s_id,
'k_id' => $kitaab,
'h_status' => 1
]);
}
}
$hadees = Hadees::create($data);
}
/**
* Checks if the baab exists in the database or not.
*
* @param Collection $baab
* @param Object $row
* @return int - baad_id or 0
*/
public function baabCheck($baab, $row){
foreach($baab as $b){
if(trim($b->b_arabic) == trim($row['baab_arabic']) || trim($b->b_urdu) == trim($row['baab_urdu']) || trim($b->b_english) == trim($row['baab_english'])){
return $b->b_id;
} else{
return 0;
}
}
}
}
当数据较少时一切正常。现在我在 Raavi table 中有 1400+ 行,在 [=] 中有 10,000+ 行35=]Baabtable。现在每当我尝试将 sheet 导入系统时,它都会给我这个错误:
Allowed memory size of 268435456 bytes exhausted (tried to allocate 37748736 bytes).
我认为这是因为 foreach() 循环太长了。任何形式的帮助将不胜感激。如果你们对糟糕的编码或糟糕的逻辑构建有任何建议,请告诉我。我在这个问题上被困了将近两天。提前致谢。
P.s:本地主机和主机上的错误相同,只是字节不同。我相信这是由于 memory_limit 设置不同造成的。
扩展您的 memory_limit
。对于 'localhost',在 php.ini
-
memory_limit=2048M
并重启你的服务器。
您可以将某些 files/pages/scripts 的 memory_limit 设置为大于 php.ini 设置的值。添加 __construct()
方法并提高内存限制:
public function __construct() {
ini_set('memory_limit', '1G'); // change as needed, as long as your system can support it
parent::__construct(); // If added in your controller. Probably not needed if you use it in your import class
}
将 memory_limit 设置为对要覆盖的特定文件无限制 php.ini memory_limit
// put it in your construct
ini_set('memory_limit', -1);
所有已发布的解决方案都提到提高 PHP 的内存限制。
不是这样的。您不能只是投入更多的 RAM 来解决问题。如果您的服务器有 2GB 的 RAM,并且您上传了一个文件,其中创建的所有数组都可以使用超过 2GB 的 RAM,该怎么办?下一步是什么?更不用说服务器 运行 内存不足和杀死其他进程的风险。例如,如果服务器共享 PHP 和 MySQL 运行ning 并且 PHP 导致服务器 运行 内存不足,OOM Killer 将启动并且 可能 终止 MySQL 进程。
您的问题的解决方案是分块处理该文件。 Laravel 6,例如,有一个新的集合类型,Lazy Collections。他们可以帮助您加快速度。您的代码可能必须更改才能使用块处理,但恕我直言,这是解决此问题的唯一方法。
我也会 运行 这在队列中,而不是来自用户请求。
我最近在 运行ning
时遇到了同样的问题
Model::insert();
我已经通过禁用查询日志和取消查询的所有事件解决了这个问题。
DB::connection('your-connection')->disableQueryLog();
DB::connection('your-connection')->unsetEventDispatcher();
但请注意,它只能在导入数据时使用。
否则,您的其他包的事件和日志系统将无法处理这两行之后的查询 运行。
大家好,
我正在使用 Laravel Excel/Maatwebsite 开发一个系统。我想要实现的是,当用户将 excel 文件插入系统时,系统将检查一些内容,然后将数据插入数据库。
这是数据库模式的一个实例:
Hadees:
h_id | h_english | r_id | h_last_raavi_id | b_id | s_id | k_id | h_status
Raavi:
r_id | r_english | r_status
Baab:
b_id | b_english | s_id | b_status
Section:
s_id | s_english | k_id | s_status
Kitaab:
k_id | k_english | k_status
我的控制器:
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\Section;
use App\Models\Raavi;
use App\Imports\HadeesImport;
use Excel;
class ImportHadeesController extends Controller{
/**
* Show the application import-hadees page.
*
* @return \Illuminate\Http\Response
*/
public function index(){
$section = Section::where(['s_status' => 1])->get();
return view('admin/import-hadees', compact('section'));
}
/**
* This method uses the Excel facade to prep the excel file
* and extract data from it and uses App\Imports\HadeesImport
* class to insert each row in the database schema accordingly.
*
* @param Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function importHadees(Request $request){
$raavi = Raavi::where(['r_status' => 1])->get();
if($request->file('hadees_sheet')) {
} else {
return response()->json(['status'=>'error', 'msg'=> 'No file present!']);
}
$temp = $request->file('hadees_sheet')->store('temp');
$path=storage_path('app').'/'.$temp;
$hadees = Excel::import(new HadeesImport($request->s_id, compact('raavi')), $path);
if($hadees){
return response()->json(['status'=>'success', 'msg'=> 'Successfully imported all the data from the file to the database!']);
} else{
return response()->json(['status'=>'error', 'msg'=> 'Unable to import data from the file to the database!']);
}
}
}
HadeesImport Class:
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use App\Models\Section;
use App\Models\Baab;
use App\Models\Hadees;
use App\Models\Raavi;
class HadeesImport implements ToCollection, WithHeadingRow{
/**
* Global variable for section_id.
*/
public $s_id;
/**
* Global variable for raavi's data.
*/
public $raavi;
/**
* Construction function.
*
* @param int $id
*/
function __construct($id, $arr) {
$this->s_id = $id;
$this->raavi = $arr;
}
/**
* This method is responsible for inserting the excel
* sheet's rows data to the database schema.
*
* @param Collection $row
*/
public function collection(Collection $rows){
$baab = Baab::where(['s_id' => $this->s_id])->get();
$hissa = Section::where(['s_id' => $this->s_id])->first();
$kitaab = $hissa->k_id;
$first_raavi = 0;
$last_raavi = 0;
$baab_id = 0;
$data = array();
foreach ($rows as $row){
if($row['hadees_arabic'] != "" && $row['hadees_urdu'] != ""){
$baab_id = $this->baabCheck($baab, $row);
foreach($this->raavi['raavi'] as $rav){
if(trim($rav->r_english) == trim($row['first_raavi_english'])){
$first_raavi = $rav->r_id;
} else{
$first_raavi = 0;
}
$last_raavi = (trim($rav->r_english) == trim($row['last_raavi_english']))? $rav->r_id : 0;
}
if($first_raavi == 0){
$raavi = Raavi::create([
'r_arabic' => trim($row['first_raavi_urdu']),
'r_urdu' => trim($row['first_raavi_urdu']),
'r_english' => trim($row['first_raavi_english']),
'r_nickname' => trim($row['raavi_other_names']),
'r_status' => 1,
]);
$first_raavi = $raavi->r_id;
}
if($last_raavi == 0){
$raavi = Raavi::create([
'r_arabic' => trim($row['last_raavi_urdu']),
'r_urdu' => trim($row['last_raavi_urdu']),
'r_english' => trim($row['last_raavi_english']),
'r_nickname' => 'n/a',
'r_status' => 1,
]);
$last_raavi = $raavi->r_id;
}
$data = array([
'h_arabic' => trim($row['hadees_arabic']),
'h_urdu' => trim($row['hadees_urdu']),
'h_english' => trim($row['hadees_english']),
'h_roman_keywords' => trim($row['roman_keywords']),
'h_number' => trim($row['hadees_number']),
'r_id' => $first_raavi,
'h_last_raavi_id' => $last_raavi,
'b_id' => $baab_id,
's_id' => $this->s_id,
'k_id' => $kitaab,
'h_status' => 1
]);
}
}
$hadees = Hadees::create($data);
}
/**
* Checks if the baab exists in the database or not.
*
* @param Collection $baab
* @param Object $row
* @return int - baad_id or 0
*/
public function baabCheck($baab, $row){
foreach($baab as $b){
if(trim($b->b_arabic) == trim($row['baab_arabic']) || trim($b->b_urdu) == trim($row['baab_urdu']) || trim($b->b_english) == trim($row['baab_english'])){
return $b->b_id;
} else{
return 0;
}
}
}
}
当数据较少时一切正常。现在我在 Raavi table 中有 1400+ 行,在 [=] 中有 10,000+ 行35=]Baabtable。现在每当我尝试将 sheet 导入系统时,它都会给我这个错误:
Allowed memory size of 268435456 bytes exhausted (tried to allocate 37748736 bytes).
我认为这是因为 foreach() 循环太长了。任何形式的帮助将不胜感激。如果你们对糟糕的编码或糟糕的逻辑构建有任何建议,请告诉我。我在这个问题上被困了将近两天。提前致谢。
P.s:本地主机和主机上的错误相同,只是字节不同。我相信这是由于 memory_limit 设置不同造成的。
扩展您的 memory_limit
。对于 'localhost',在 php.ini
-
memory_limit=2048M
并重启你的服务器。
您可以将某些 files/pages/scripts 的 memory_limit 设置为大于 php.ini 设置的值。添加 __construct()
方法并提高内存限制:
public function __construct() {
ini_set('memory_limit', '1G'); // change as needed, as long as your system can support it
parent::__construct(); // If added in your controller. Probably not needed if you use it in your import class
}
将 memory_limit 设置为对要覆盖的特定文件无限制 php.ini memory_limit
// put it in your construct
ini_set('memory_limit', -1);
所有已发布的解决方案都提到提高 PHP 的内存限制。
不是这样的。您不能只是投入更多的 RAM 来解决问题。如果您的服务器有 2GB 的 RAM,并且您上传了一个文件,其中创建的所有数组都可以使用超过 2GB 的 RAM,该怎么办?下一步是什么?更不用说服务器 运行 内存不足和杀死其他进程的风险。例如,如果服务器共享 PHP 和 MySQL 运行ning 并且 PHP 导致服务器 运行 内存不足,OOM Killer 将启动并且 可能 终止 MySQL 进程。
您的问题的解决方案是分块处理该文件。 Laravel 6,例如,有一个新的集合类型,Lazy Collections。他们可以帮助您加快速度。您的代码可能必须更改才能使用块处理,但恕我直言,这是解决此问题的唯一方法。
我也会 运行 这在队列中,而不是来自用户请求。
我最近在 运行ning
时遇到了同样的问题Model::insert();
我已经通过禁用查询日志和取消查询的所有事件解决了这个问题。
DB::connection('your-connection')->disableQueryLog();
DB::connection('your-connection')->unsetEventDispatcher();
但请注意,它只能在导入数据时使用。 否则,您的其他包的事件和日志系统将无法处理这两行之后的查询 运行。