我使用phpexcel时遇到问题。我必须将记录转换为excel并下载。问题是这个过程很慢。我测试了2000 - 3000条记录,将时间限制设置为0,内存限制设置为256M,但处理和下载需要超过30分钟。我在网上看到其他人可以在10秒内下载大约6000条记录。
请有人帮助我。代码有什么问题?
这是控制器:
function download_aplikasi()
{
$this->Weblog_m->save_log_m("Download aplikasi");
$data_aplikasi = $this->Io_excel_m->get_aplikasi_m();
// Create new PHPExcel object
$objPHPExcel = new PHPExcel();
$objPHPExcel->getActiveSheet()->getStyle('1:1')->getFont()->setBold(true);
// Add some data
$objPHPExcel->setActiveSheetIndex(0)
->setCellValue('A1', 'TGL_APLIKASI')
->setCellValue('B1', 'CD_CABANG')
->setCellValue('C1', 'NAMA_CABANG')
->setCellValue('D1', 'NIP')
->setCellValue('E1', 'NAMA_PEGAWAI')
->setCellValue('F1', 'JABATAN')
->setCellValue('G1', 'NAMA_NASABAH')
->setCellValue('H1', 'NO_REK')
->setCellValue('I1', 'NO_CIF')
->setCellValue('J1', 'DOB_NASABAH')
->setCellValue('K1', 'JNS_NASABAH')
->setCellValue('L1', 'NOMINAL')
->setCellValue('M1', 'ID_NASABAH')
->setCellValue('N1', 'PRODUK')
->setCellValue('O1', 'JNS_PINJAMAN')
->setCellValue('P1', 'JNS_USAHA')
->setCellValue('Q1', 'LAMA_USAHA')
->setCellValue('R1', 'JNS_JAMINAN')
->setCellValue('S1', 'PIC_NASABAH')
->setCellValue('T1', 'TELP_NASABAH')
->setCellValue('U1', 'NAMA_TOKO')
->setCellValue('V1', 'KATEGORI')
->setCellValue('W1', 'CATATAN')
->setCellValue('X1', 'KETERANGAN')
->setCellValue('Y1', 'PIC_UNIT')
->setCellValue('Z1', 'TELP_PIC')
->setCellValue('AA1', 'KAT_PRODUK')
->setCellValue('AB1', 'PROGRESS')
->setCellValue('AC1', 'PROGRESS_NOTE');
$i = 1;
if (count($data_aplikasi) > 0)
{
foreach ($data_aplikasi as $row_aplikasi)
{
$data_pic = $this->App_m->detilpic_m($row_aplikasi->idpic);
$i = $i + 1;
$objPHPExcel->setActiveSheetIndex(0)
->setCellValue('A'.$i, date("d/m/Y", strtotime($row_aplikasi->tglaplikasi)))
->setCellValue('B'.$i, $row_aplikasi->cdcabang)
->setCellValue('C'.$i, $row_aplikasi->namacabang)
->setCellValue('D'.$i, $row_aplikasi->nip)
->setCellValue('E'.$i, $row_aplikasi->nama_user)
->setCellValue('F'.$i, $row_aplikasi->namajabatan)
->setCellValue('G'.$i, $row_aplikasi->nama_nasabah)
->setCellValue('H'.$i, $row_aplikasi->norek)
->setCellValue('I'.$i, $row_aplikasi->nocif)
->setCellValue('J'.$i, $row_aplikasi->tgllahir)
->setCellValue('K'.$i, $row_aplikasi->jnsnasabah)
->setCellValue('L'.$i, $row_aplikasi->nominal_aplikasi)
->setCellValue('M'.$i, $row_aplikasi->ktpnasabah)
->setCellValue('N'.$i, $row_aplikasi->produk)
->setCellValue('O'.$i, $row_aplikasi->jnspinjaman)
->setCellValue('P'.$i, $row_aplikasi->jnsusaha)
->setCellValue('Q'.$i, $row_aplikasi->lamausaha)
->setCellValue('R'.$i, $row_aplikasi->jnsjaminan)
->setCellValue('S'.$i, $row_aplikasi->pic_nasabah)
->setCellValue('T'.$i, $row_aplikasi->telpnasabah)
->setCellValue('U'.$i, $row_aplikasi->namatoko)
->setCellValue('V'.$i, $row_aplikasi->kategori)
->setCellValue('W'.$i, $row_aplikasi->catatan)
->setCellValue('X'.$i, $row_aplikasi->keterangan)
->setCellValue('Y'.$i, $data_pic->nama_user)
->setCellValue('Z'.$i, $data_pic->nomorhp)
->setCellValue('AA'.$i, $row_aplikasi->namaproduct)
->setCellValue('AB'.$i, $row_aplikasi->progress)
->setCellValue('AC'.$i, $row_aplikasi->progress_note);
}
}
else $objPHPExcel->setActiveSheetIndex(0)
->setCellValue('A2', 'No Record Found');
// Rename worksheet
$objPHPExcel->getActiveSheet()->setTitle('Aplikasi');
// Set active sheet index to the first sheet, so Excel opens this as the first sheet
$objPHPExcel->setActiveSheetIndex(0);
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="Aplikasi_'.$this->input->post("bulan_kinerja").'.xlsx"');
header('Cache-Control: max-age=0');
header('Cache-Control: max-age=1');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
header('Pragma: public'); // HTTP/1.0
$objWriter = IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->save('php://output');
exit;
}
这是型号:
function get_aplikasi_m()
{
$periode = $this->input->post("bulan_kinerja");
$idcabang = $this->input->post("id_cabang");
$cek_cabang = $this->cek_cabang_m($idcabang);
$this->db->select('*');
$this->db->from("tbl_aplikasi");
$this->db->join("tbl_user", "tbl_user.iduser = tbl_aplikasi.iduser", "Left");
$this->db->join("tbl_product", "tbl_product.idproduct = tbl_aplikasi.idproduct", "Left");
$this->db->join("tbl_jabatan", "tbl_user.idjabatan = tbl_jabatan.idjabatan", "Left");
$this->db->join("tbl_unit", "tbl_product.idunit = tbl_unit.idunit", "Left");
$this->db->join("tbl_cabang", "tbl_user.idcabang = tbl_cabang.idcabang", "Left");
$this->db->where("tbl_aplikasi.statusapproval='approve'");
$this->db->where("MONTH(tbl_aplikasi.tglaplikasi)", date("m", strtotime($periode)));
$this->db->where("YEAR(tbl_aplikasi.tglaplikasi)", date("Y", strtotime($periode)));
if ($cek_cabang->jnscabang != "area") $this->db->where("tbl_aplikasi.idcabang", $idcabang);
$this->db->order_by("tbl_aplikasi.tglaplikasi", "desc");
return $query = $this->db->get()->result();
}
function getpic_m($idunit)
{
$this->db->select('*');
$this->db->from("tbl_user");
$this->db->join("tbl_jabatan", "tbl_user.idjabatan = tbl_jabatan.idjabatan", "Left");
$this->db->join("tbl_cabang", "tbl_cabang.idcabang = tbl_user.idcabang", "Left");
$this->db->where("tbl_user.idunit", $idunit);
$this->db->where("tbl_user.accstat='active'");
$this->db->order_by("tbl_user.nama_user", "asc");
return $query = $this->db->get();
}
答案 0 :(得分:1)
PHPExcel很旧,没有维护。它已被替换为名为PHPSpreadsheet的新版本,您应该使用该版本。对我来说,它更快,更可靠。
转换起来很容易,因为大部分功能完全相同。不需要进行大量的重写。主要的变化是创建读者,作家,工作簿和工作表对象。
我将继续使用PHPExcel来获得这个答案。
您可以采取一些措施来优化代码。首先,捕获活动工作表对象以供重用,而不是重复调用setActiveSheetIndex()
和getActiveSheet()
。
// Create new PHPExcel object
$objPHPExcel = new PHPExcel();
// A new workbook always sets the active sheet index to the first sheet
// Capture the "active sheet" object for easy reuse.
$activeSheet = $objPHPExcel->getActiveSheet();
尽可能尝试使用数组而不是多次调用setCellValue()
来设置单元格值块。例如:
// Add some data
$rowArray = ['TGL_APLIKASI', 'CD_CABANG', 'NAMA_CABANG', 'NIP',
'NAMA_PEGAWAI', 'JABATAN', 'NAMA_NASABAH', 'NO_REK', 'NO_CIF',
'DOB_NASABAH', 'JNS_NASABAH', 'NOMINAL', 'ID_NASABAH', 'PRODUK',
'JNS_PINJAMAN', 'JNS_USAHA', 'LAMA_USAHA', 'JNS_JAMINAN',
'PIC_NASABAH', 'TELP_NASABAH', 'NAMA_TOKO', 'KATEGORI',
'CATATAN', 'KETERANGAN', 'PIC_UNIT', 'TELP_PIC', 'KAT_PRODUK',
'PROGRESS', 'PROGRESS_NOTE'];
//add the array to the activesheet
$activeSheet->fromArray($rowArray, NULL, 'A1');
了解Setting a Range of Cells from an Array
您也可以使用fromArray()
添加数据库结果,但需要更改模型。您的模型使用result()
返回一个对象数组。如果您返回result_array()
,则可以轻松地使用数据通过一次调用应用所有行。
将function get_aplikasi_m()
的最后一行更改为此
return $this->db->get()->result_array();
但是你有两个并发症。首先是第一列中日期的格式。你可以,并且可能应该修改你的查询,以便在数据检索期间执行此操作。但我不知道如何做到这一点。
第二个复杂因素是添加$data_pic
个项目。如果App_m->detilpic_m()
返回result_array()
会更容易,但我会按原样继续。
从模型数据中添加行和列然后如下所示。
$data_aplikasi = $this->Io_excel_m->get_aplikasi_m();
if (count($data_aplikasi) > 0)
{
//walk through all records to format date and add pic data
foreach ($data_aplikasi as $key => $row_aplikasi)
{
// format the date and make sure the
// main array is updated with the change
$data_aplikasi[$key]['tglaplikasi'] = date("d/m/Y", strtotime($row_aplikasi['tglaplikasi']));
$data_pic = $this->App_m->detilpic_m($row_aplikasi['idpic']);
//make an array from $data_pic values
$pic_data = [$data_pic->nama_user, $data_pic->nomorhp];
//get the index where pic data should be inserted
$index = array_search("keterangan", array_keys($row_aplikasi));
// insert $pic_data into $row_aplikasi at the right place
// and update the model result at the same time
$data_aplikasi[$key] = array_splice($row_aplikasi, $index, 0, $pic_data);
}
//add $data_aplikasi array to the activesheet with one call
$activeSheet->fromArray($data_aplikasi, NULL, 'A2');
}
else
{
$activeSheet->setCellValue('A2', 'No Record Found');
}
我希望评论能够清楚地说明发生了什么。这是整个功能,所以你可以一次看到它。
public function download_aplikasi()
{
$this->Weblog_m->save_log_m("Download aplikasi");
// Create new PHPExcel object
$objPHPExcel = new PHPExcel();
// A new workbook always sets the active sheet index to the first sheet
// Capture the "active sheet" object sheet
$activeSheet = $objPHPExcel->getActiveSheet();
// Name the worksheet
$activeSheet->setTitle('Aplikasi');
$activeSheet->getStyle('1:1')->getFont()->setBold(true);
// Add some data
$rowArray = ['TGL_APLIKASI', 'CD_CABANG', 'NAMA_CABANG', 'NIP',
'NAMA_PEGAWAI', 'JABATAN', 'NAMA_NASABAH', 'NO_REK', 'NO_CIF',
'DOB_NASABAH', 'JNS_NASABAH', 'NOMINAL', 'ID_NASABAH', 'PRODUK',
'JNS_PINJAMAN', 'JNS_USAHA', 'LAMA_USAHA', 'JNS_JAMINAN',
'PIC_NASABAH', 'TELP_NASABAH', 'NAMA_TOKO', 'KATEGORI',
'CATATAN', 'KETERANGAN', 'PIC_UNIT', 'TELP_PIC', 'KAT_PRODUK',
'PROGRESS', 'PROGRESS_NOTE'];
//add the array to the activesheet
$activeSheet->fromArray($rowArray, NULL, 'A1');
$data_aplikasi = $this->Io_excel_m->get_aplikasi_m();
if (count($data_aplikasi) > 0)
{
//walk through all records to format date and add pic data
foreach ($data_aplikasi as $key => $row_aplikasi)
{
// format the date and make sure the
// main array is updated with the change
$data_aplikasi[$key]['tglaplikasi'] = date("d/m/Y", strtotime($row_aplikasi['tglaplikasi']));
$data_pic = $this->App_m->detilpic_m($row_aplikasi['idpic']);
//make an array from $data_pic values
$pic_data = [$data_pic->nama_user, $data_pic->nomorhp];
//get the index where pic data should be inserted
$index = array_search("keterangan", array_keys($row_aplikasi));
// insert $pic_data into $row_aplikasi at the right place
// and update the model result at the same time
$data_aplikasi[$key] = array_splice($row_aplikasi, $index, 0, $pic_data);
}
//add $data_aplikasi array to the activesheet with one call
$activeSheet->fromArray($data_aplikasi, NULL, 'A2');
}
else
{
$activeSheet->setCellValue('A2', 'No Record Found');
}
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="Aplikasi_'.$this->input->post("bulan_kinerja").'.xlsx"');
header('Cache-Control: max-age=0');
header('Cache-Control: max-age=1');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
header('Pragma: public'); // HTTP/1.0
$objWriter = IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->save('php://output');
//Don't use exit, let CI finish as designed by letting the controller return
//exit;
}
我假设$this->Io_excel_m->get_aplikasi_m()
按照您在原始代码中使用的顺序返回字段。如果字段不是那个顺序,您将不得不重新排列$data_aplikasi
或更改查询,以便字段按您想要的顺序排列。就个人而言,我会做第二个。
很难确定,但看起来你可以在调用$data_pic
期间修改查询(使用JOIN)来获取get_aplikasi_m()
字段。
日期字段也可以您想要的格式从查询中返回。
这两个模型更改将消除用于修改foreach
的{{1}}循环。执行将更快,因为您删除了数千个数据库调用以获取data_aplikasi
。通常,最好不要在循环内部进行查询 - 它需要大量的系统资源和时间。
我没有测试过这段代码(没有数据)所以很可能存在逻辑和语法错误。这个概念是合理的,是我成功使用的一种技术。