【问题标题】:How to optimize a wp_query to csv script?如何优化 wp_query 到 csv 脚本?
【发布时间】:2014-12-10 22:47:46
【问题描述】:

我制作了这个脚本,我在其中运行了一个 WP_Query(),它可能会获得 2,000 条记录并且还在增长。我希望能够将这些结果写入 CSV 文件。当 posts_per_page 设置为 300 或更少的记录时,我可以正常工作。

如果我将 posts_per_page 更改为 -1,则会出现此错误:

Fatal error: Allowed memory size of 134217728 bytes exhausted

我想知道是否有一种方法可以一次将 300 条记录发送到 CSV 文件,直到没有更多记录然后触发文件下载?

或者也许将每一行流式传输到 CSV 文件?执行 fopencsv 时管理内存的最佳方法是什么?

这是我现在拥有的:

$export_query = array(
    'post_type' => 'videorepot',
    'posts_per_page' => -1,
    'status' => 'published',
    'meta_query' => array(
        array(
            'key'     => 'agree',
            'value'   => 1,
            'compare' => '=',
        ),
        array(
            'key'     => 'opt-in',
            'value'   => 1,
            'compare' => '=',
        ),
        array(
            'key'     => 'status',
            'value'   => 'Video Ready',
            'compare' => '=',
        ),
    )
);

// Posts query
$wp_query = new WP_Query( $export_query );
if ( $wp_query->have_posts() ) :
    $list = array( 'Email,Photo1,Photo2,Photo3,VideoURL' );
    while ( $wp_query->have_posts() ) : $wp_query->the_post();

        $postID = get_the_ID();

        $user_email = get_post_meta($postID, 'user_email', true);
        $photo1 = get_post_meta($postID, 'photo1', true);
        $photo2 = get_post_meta($postID, 'photo2', true);
        $photo3 = get_post_meta($postID, 'photo3', true);
        $videourl = get_post_meta($postID, 'video_file', true);

        $list[] = $user_email.','.$photo1.','.$photo2.','.$photo3.','.$videourl;

    endwhile;
endif;


// Output file stream
$output_filename = 'export_' . strftime( '%Y-%m-%d' )  . '.csv';
$output_handle = @fopen( $output_filename, 'w' );

header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
header( 'Content-Description: File Transfer' );
header( 'Content-type: text/csv' );
header( 'Content-Disposition: attachment; filename=' . $output_filename );
header( 'Expires: 0' );
header( 'Pragma: public' );

foreach ( $list as $line ) {

    // Add row to file
    fputcsv( $output_handle, explode(',', $line), ',', '"');

}

// Close output file stream
fclose( $output_handle );

// We're done!
exit;

更新 #1 对于一些测试,我删除了将项目写入 CSV 文件的脚本部分,所以我发现它在我的查询中确实有一些东西让它变得疯狂。我的自定义帖子类型中可能有 3000 条记录。为什么这会使我的查询内存不足?

更新 #2

我决定走另一条路,因为我在使用 wp_query 时仍然遇到内存问题。所以,我编写了我的 mySQL 查询——你知道我是从其他示例中将它一起破解的。这个查询运行得非常快,所以我想我的运气会更好。

我有一个与 meta_key/meta_values 相关的新问题。目前,我在查询中使用 SELECT *,但我不想选择所有内容。我只需要数据库中的大约 5 个字段。我想要的其中一些字段是 meta_key/meta_value。有没有办法可以指定这些 meta_keys,这样当我导出表时,我只能得到 5 列的结果?

我的查询现在看起来像这样:

$values = mysql_query("SELECT * FROM wp_posts 
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) 
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id) 
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id) WHERE 1=1 
AND ( ( post_date >= '2014-11-03 00:00:00' AND post_date <= '2014-12-31 23:59:59' ) ) 
AND wp_posts.post_type = 'videorepot' 
AND (wp_posts.post_status = 'publish') 
AND ( (wp_postmeta.meta_key = 'agree' AND CAST(wp_postmeta.meta_value AS CHAR) = '1') 
AND (mt1.meta_key = 'opt-in' AND CAST(mt1.meta_value AS CHAR) = '1') 
AND (mt2.meta_key = 'status' AND CAST(mt2.meta_value AS CHAR) = 'Video Ready') ) 
GROUP BY wp_posts.ID 
ORDER BY wp_posts.post_date DESC 
LIMIT 0,20");

现在我将限制设置为 20,但我已经将限制设置为 0,9999 进行了测试,它在 phpmyadmin 中运行得非常快。当我没有设置限制时,上面的查询给了我大约 1282 个结果。

更新 #3

我已经发布了我的答案的解决方案。感谢您的帮助,大卫。

【问题讨论】:

  • 增加 php 内存...或者添加 post meta 以表示您已下载并将最大结果设置为 200 左右(不包括下载)
  • 我不想简单地增加 php 内存。我有兴趣学习在这种情况下管理内存的正确 PHP 技术。不过我会暂时试试这个。另外根据我允许使用 134 MB 内存的错误,我认为这是相当高的。问题是每次单击链接时我都想导出完整的数据库,因此无需将项目设置为正在下载。尽管如此,还是感谢您的评论。
  • true 但您没有 134 mb 可使用...但在循环后取消设置 wp 查询并使用 while 而不是 foreach (foreach 再次创建另一个副本,因此您实际上有 3 个副本在旅途中),然后在循环遍历它时取消设置 $list 数组。
  • 好的。我在循环之后添加了 wp_reset_query() 以重置 wp_query。我对使用“while”而不是“foreach”有点困惑,因为我将查询结果加载到数组中,然后使用 foreach 将每个项目添加到 CSV。我可以尝试删除 foreach 并将 fputcsv 移动到“While”循环中。也许这就是你的意思?我确定某处可能有一个 unset($list) 函数,我会查一下。谢谢。
  • foreach 创建数据的副本,而在没有副本的情况下循环数据。实际上,您实际上可以使用 wp while 循环,这可以节省循环两次。希望您不需要在每次迭代时取消设置值,只需在循环结束时重置发布数据。

标签: php wordpress csv memory-management fputcsv


【解决方案1】:

我认为我已经找到了一个很好的解决方案。这对我有用,我不必增加 php 内存或类似的东西。

这是最终的未经编辑的脚本。请记住,我使用的 mysql 查询使用日期范围和 3 个元键从我们的数据库中获取数据子集。我收到了大约 1290 个结果,全部写入 CSV 文件。 (感谢大卫的协助。)

$path = $_SERVER['DOCUMENT_ROOT'];

include_once $path . '/wp-load.php';

// SET UP DB VARS
$host = DB_HOST;
$user = DB_USER;
$pass = DB_PASSWORD;
$db = DB_NAME;


// CONNECT TO DB
$link = mysql_connect($host, $user, $pass) or die("Can not connect." . mysql_error());
mysql_select_db($db) or die("Can not connect.");

$mycolums = array( 'Email,Photo1,Photo2,Photo3,VideoURL' );
foreach ( $mycolums as $column ) {
    $csv_output = $column.", ";
}
$csv_output .= "\n";

$values = mysql_query("SELECT * FROM wp_posts 
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) 
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id) 
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id) WHERE 1=1 
AND ( ( post_date >= '2014-11-03 00:00:00' AND post_date <= '2014-12-31 23:59:59' ) ) 
AND wp_posts.post_type = 'videorepot' 
AND (wp_posts.post_status = 'publish') 
AND ( (wp_postmeta.meta_key = 'agree' AND CAST(wp_postmeta.meta_value AS CHAR) = '1') 
AND (mt1.meta_key = 'opt-in' AND CAST(mt1.meta_value AS CHAR) = '1') 
AND (mt2.meta_key = 'status' AND CAST(mt2.meta_value AS CHAR) = 'Video Ready') ) 
GROUP BY wp_posts.ID 
ORDER BY wp_posts.post_date DESC 
LIMIT 0,9999");
while ($rowr = mysql_fetch_row($values)) {

        $postID = $rowr[0];         
        $user_email = get_post_meta($postID, 'email_address', true);
        $photo1 = get_post_meta($postID, 'photo_1', true);
        $photo2 = get_post_meta($postID, 'photo_2', true);
        $photo3 = get_post_meta($postID, 'photo_3', true);
        $videourl = get_post_meta($postID, 'the_video', true);

        // $csv_output .= $rowr['']."; ";
        $csv_output .= $user_email.', '.$photo1.', '.$photo2.', '.$photo3.', '.$videourl.',';
        $csv_output .= "\n";

}

$output_filename = "export_".date("Y-m-d_H-i",time()).".csv";
header("Content-type: application/vnd.ms-excel");
header("Content-disposition: csv" . date("Y-m-d_H-i",time()) . ".csv");
header( "Content-disposition: filename=".$output_filename);
print_r($csv_output);
exit;

我希望这对正在处理记忆问题的其他人有所帮助。

【讨论】:

    【解决方案2】:

    我也收到“试图分配更多内存致命错误”,但我的解决方案是在 while 循环中我错过了这一行:

    $wp_query->the_post();
    

    如果其他人也面临同样的问题,可能会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-20
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 2016-09-13
      • 2018-07-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多