我正在使用TCPDF即时创建PDF文档。 生成这些 PDF 的一些查询包含超过 1,000+ 条记录,我的服务器因较大的查询而超时(内部服务器错误)。 我正在使用PHP和MySQL。
如何使用 AJAX 将大型 MySQL 查询解析为较小的块,缓存数据并重新组合结果,以防止服务器超时?
这是我当前的代码:
require_once('../../libraries/tcpdf/tcpdf.php');
$pdf = new TCPDF();
$prows = fetch_data($id);
$filename = '../../pdf_template.php';
foreach ($prows AS $row) {
$pdf->AddPage('P', 'Letter');
ob_start();
require($filename);
$html .= ob_get_contents();
ob_end_clean();
$pdf->writeHTML($html, true, false, true, false, '')
}
$pdf->Output('documents.pdf', 'D');
如果每次调用时都必须生成数据,则可以将查询分成 100 行的块,将数据缓存在文件系统上(或者更好的是,在 APC/WinCache/XCache/MemCache 中),然后在最终的 AJAX 调用中缓存 (Finalquery=true),加载缓存,生成 PDF 并清除缓存。
我假设您无法像<?php set_time_limit(0);
那样更改脚本的最大运行时间
流程将如下所示:
- 为查询操作生成唯一 ID
- 在客户端,通过对 PHP 脚本的初始调用获取最大行数(选择计数...等)。 然后,将其除以 10、100
- 、1000,无论您要将它分成多少个请求。
- 使用唯一 id 对其中每个区块(第 0、100、100,200 行)运行 AJAX 请求。
- 在服务器端,您选择该行的数量/选择,然后将其放入某个商店中。我熟悉WinCache(我一直在Windows上开发PHP......),所以把它添加到用户缓存中:
wincache_ucache_add( $uniqueId . '.chunk' . $chunkNumber, $rows);
- 同时,在客户端,跟踪所有 AJAX 请求。完成每个操作后,调用生成 PDF 函数服务器端。给出区块数和唯一 ID。
- 在服务器端,从缓存中获取所有内容。
$rows = array_merge( wincache_ucache_get($uniqueId . '.chunk'. $chunkNumber1), wincache_ucache_get($uniqueId . '.chunk'. $chunkNumber2) );
- 清除缓存:
wincache_ucache_clear();
- 生成 PDF 并返回。
请注意,您实际上应该只是手动或通过抽象层或ORM中的功能缓存查询结果。
尝试像PEAR cache_lite这样的简单缓存。在慢速或关闭期间,您可以创建一个实用程序来运行和缓存所需的所有记录。然后,当用户请求 PDF 时,您可以访问缓存数据,而无需访问数据库。此外,您可以只使用表上的时间戳字段并请求自数据缓存以来已更改的数据库记录,这将显着降低您必须从数据库中实时检索的当前记录计数。
<?php
include 'Cache/Lite/Output.php';
$options = array(
'cacheDir' => '/tmp/cache/',
'lifeTime' => 3600,
'pearErrorMode' => CACHE_LITE_ERROR_DIE,
'automaticSerialization' => true
);
$cache = new Cache_Lite_Output($options);
if( $data_array = $cache->get('some_data_id') ) {
$prows = $data_array;
} else {
$prows = fetch_data($id);
$cache->save($prows);
}
print_r($prows);
?>