【问题标题】:How to break up a large MySQL query and cache data with AJAX?如何使用 AJAX 分解大型 MySQL 查询和缓存数据?
【发布时间】:2012-06-27 07:48:21
【问题描述】:

我正在使用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');

【问题讨论】:

  • 你能把它作为一个预定的 mysql 作业/事件来运行吗?
  • @DavidCheung 你的意思是通过 Cron 工作吗?不,这需要根据用户的操作生成。

标签: php mysql ajax timeout


【解决方案1】:

如果在调用它时每次都必须生成数据,您可以将查询分块为 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 中的功能。

【讨论】:

  • 我无法更改最长运行时间。您所描述的主要内容听起来会起作用;但是,对于如何“在文件系统上缓存数据”仍然有些困惑。你能详细描述一下吗?
【解决方案2】:

尝试像 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);

?>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-25
    • 2012-11-16
    • 2013-04-09
    • 1970-01-01
    • 2012-04-28
    • 1970-01-01
    • 2020-04-21
    • 2015-06-27
    相关资源
    最近更新 更多