【问题标题】:Wordpress query with 19000+ products包含 19000 多种产品的 Wordpress 查询
【发布时间】:2018-10-22 00:17:30
【问题描述】:

我的 Wordpress 查询有问题。

我想做什么:

我有包含产品数据(名称、价格、库存、sku 等)的 CSV 文件 我想导入这个文件,但是当我试图通过 SKU 获取产品 ID 时,我的查询对于我的服务器来说太高了,但我做了一些愚蠢的想法:在 foreach 中我试图获取所有 product_id。

是否可以在不终止服务器的情况下拆分我的 wp 查询? 我正在尝试睡觉,但这没有结果...

我的代码在这里:

    public function new_import_stock_prices(){
    global $wpdb;
    global $post;

    if ( !function_exists( 'wc_get_product_id_by_sku' ) ) { 
        require_once '/includes/wc-product-functions.php'; 
    } 

    echo '<h1>Import stanów magazynowych i cen z pliku CSV </h1>';
    echo '<h4>Plik pobierany jest z netis/products.csv</h4>';
    $fn = 'https://e-xxxxx.pl/xxx/products.csv';
    $file_array = file($fn);
    echo '<table>';
    echo '<tr>';
    echo '<td>LP</td>';
    echo '<td>Nazwa</td>';
    echo '<td>SKU</td>';
    echo '<td>Stan magazynowy</td>';
    echo '<td>Cena</td>';
    echo '<td>Product ID</td>';
    $i = 1;
    if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {

    foreach ($file_array as $line_number =>&$line)
        {
            if ($line_number > 0 && $line_number % 10 == 0) {

                $row2=explode('|',$line);
                $sku = $row2[1];
                // get the product ID from the SKU
                $product_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_sku' AND meta_value='%s' LIMIT 1", $sku ) );        
                // Get an instance of the WC_Product object
                $product = new WC_Product( $product_id );

                //Get product stock quantity and stock status
                $stock_quantity = $product->get_stock_quantity();
                $stock_status   = $product->get_stock_status();

                echo '<tr>';
                echo '<td>'.$i.'</td>';
                echo '<td>'.$row2[0].'</td>';
                echo '<td>'.$row2[1].'</td>';
                echo '<td>'.$row2[5].'</td>';
                echo '<td>'.$row2[2].'</td>';
                echo '<td>'.$product_id.'</td>';

                echo '</tr>';
                $i = $i +1;
                sleep(10);
            }
        }
    }
    echo '</table>';
}

顺便说一句。我的 wp_postmeta 表有 ~900 000+ 条记录:O

【问题讨论】:

  • I'm trying sleep but this is no result... 这与您想要做的相反。 3(ish)事情会在这里伤害你memory_limittime_limit以及浏览器的缓冲区。您可以稍微更改它们,但它们的修复效果很差。
  • And I want to import this file, 我看不到您将其保存在哪里(除非我在某处错过了WC_Product::save()),我看到您正在输出它。那么是输出还是保存呢。
  • 内存限制为10240m,时间限制为1000
  • 因此,您尝试一次读取整个文件,此外您的服务器内存与浏览器的客户端内存无关。
  • @ArtisticPhoenix 首先我想显示所有产品 id,以检查它是否正确。下一步是更改库存、价格和保存产品。这是我的第一个插件 :)

标签: php mysql wordpress woocommerce


【解决方案1】:

我想导入这个文件

我没有看到任何用于导入的代码,我看到了用于显示的代码。假设通过导入,您的意思是显示:

可能发生的只是几件事之一。

  • 你的内存不足(你应该得到一个错误)
    • 不要使用file($fn)使用打开文件逐行读取的文件函数,如fgetcsv
  • 你的时间不多了
    • 您对此无能为力,除了发送更少的数据
  • 您通过发送大量输出来压倒浏览器缓冲区。
    • 同样,您对此无能为力,但发送的数据更少。

唯一真正的解决方案(假设通过导入,您的意思是显示)是分页数据。

现在即使在文件中您也可以分页数据,但我建议使用 SQLFileObject 而不是过程文件函数。也就是说,您可以使用程序样式进行分页,但它是按字节偏移量,而不是页码。

虽然我无法编写整个分页系统,但我可以给你一些提示:

例如

//hard to tell how many lines in the file
$fn = 'https://e-xxxxx.pl/xxx/products.csv';
$f = fopen($fn, 'r');
fseek($f, $_GET['offset']); //seek to a byte offset
$i=0;
while(!feof($f) && ($row=fgetcsv($f)) && null !== $row[0]){

   if($i==10)
       $offset = ftell($f); //get byte offset

   ++$i;
}

ftellfseek 允许您获取或移动文件指针(以字节为单位)。因此,您可以从预定义的偏移量开始读取,您可以在 url ... 等中传递该偏移量。

你可以用 SplFileObject 做同样的事情,但要好一点。

try {
    $fn = 'https://e-xxxxx.pl/xxx/products.csv';
    $csv  = new SplFileObject($fn, 'r');
} catch (RuntimeException $e ) {
    printf("Error openning csv: %s\n", $e->getMessage());
}

$csv->seek($_GET['line']); //seek to a predefined line

while(!$csv->eof() && ($row = $csv->fgetcsv()) && null !== $row[0]) {
    if(($csv->key()-$_GET['line'])==10) 
        $line = $csv->key(); //get line offset
   ++$i;
}

SPL 的主要优点是您可以使用行号,这更容易使用。

你也可以像这样获取文件的总行数

$csv->seek(PHP_INT_MAX);
$total = $csv->key();
$csv->rewind(); //or $csv->seek($_GET['line'])

基本上这会寻求 PHP 可以处理的最大可能的 INT,但由于文件是固定长度的,它会将指针放在文件末尾,然后使用 key 我们可以得到行号。然后我们简单地倒退到我们想要阅读的地方。

我提到总行数是因为在分页中能够显示这一点很好。

另一个选项(显示)

除了分页之外就是不缓冲地输出页面。

 // Turn off output buffering
 ini_set('output_buffering', 'off');
 // Turn off PHP output compression
 ini_set('zlib.output_compression', false);

 //Flush (send) the output buffer and turn off output buffering
 //ob_end_flush();
 while (ob_get_level()) ob_end_flush();

 // Implicitly flush the buffer(s)
 ini_set('implicit_flush', true);
 ob_implicit_flush(true);

将此与我上面展示的方法之一结合起来,一次读取文件 1 行,您最终可能能够读取所有这些数据。

保存

为了保存数据,您可能需要将其分成多个批次,在这里可以完成与分页相同的事情(使用偏移量或行)。这样您一次只能导入几千行。我还建议不要输出数据,因为您可以给浏览器更多的缓冲区,然后它可以处理和锁定它。但是,如果您对数据进行分页,则可以将其分成足够小的块以便浏览器可以处理。

您甚至可以使用连续的 AJAX 调用自动执行此操作。基本上你会调用后端的代码来保存一定数量的行(x)。服务器会响应,然后您将再次调用 (x) 更多行,保存并重复。

我想显示所有产品 id,以检查它是否正确。下一步是更改库存、价格和节省产品

在 excel 之类的东西中完成这项工作会更容易,只是从数据输入的角度来看,没有人想编辑网页上的数千行然后让他们的会话超时或类似的东西。

希望对您有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-12
    • 1970-01-01
    • 1970-01-01
    • 2018-04-06
    • 1970-01-01
    • 2012-07-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多