【问题标题】:Massive MySQL update best approach?大规模 MySQL 更新的最佳方法?
【发布时间】:2013-06-04 06:03:36
【问题描述】:

我需要每天 3 次从 CSV 文件更新我的 MySQL 数据库中的库存水平。

CSV 中有超过 27,000 种产品需要更新,您可以想象这需要一点时间。

我目前有一个运行以下内容的 php 脚本:

select * from products where product_code = "xxxxxxx";
if num_rows > 0
    if new_stock_level = 0
        UPDATE products SET `stock` = 0, `price` = 9.99 where product_code = "xxxxxxx";
    else
        UPDATE products SET `stock` = 50, `price` = 9.99, `stock_date` = now() where product_code = "xxxxxxx";

如果您要更新

更新此量表的最佳方法是什么?

我一直在做一些研究,从我可以看到 mysqli 准备好的状态似乎是我应该去的地方。

在尝试了下面提到的一些位以及我在网上阅读的内容后,我得到了以下结果,其中包含 250 次更新。

从 InnoDB 更改为 MyISAM 平均每秒将 ubdate 数量从 7 个增加到 27 个,这从一开始是一个巨大的增长。

准备 9-10 秒的陈述

## Prepare the statment.
$stmt = $mysqli->prepare("UPDATE products SET stock = case ? when 0 then 0 else ? end, price = ?, stock_date = case ? when 0 then stock_date else now() end WHERE product_code = ?");
$stmt->bind_param('dddds', $stock, $stock, $price, $stock, $prod);
$stmt->execute();

非准备语句 9-10 秒

$sql = "UPDATE products SET stock = case " . $stock . " when 0 then 0 else " . $stock . " end, price = " . $price . ", stock_date = case " . $stock . " when 0 then stock_date else now() end WHERE product_code = \"" . $prod . "\";\n";
$mysqli->query($sql);

在 50 秒内对语句进行分组并使用 multi_query 9-10 秒执行

$mysqli->multi_query($sql);

根据我是否更新库存日期,不准备使用 2 个单独的查询。 8-9 秒

if($stock > 0)
{
    $sql = "UPDATE products SET stock = " . $stock . ", price = " . $price . ", stock_date = now() WHERE product_code = \"" . $prod . "\";\n";
}
else
{   
    $sql = "UPDATE products SET stock = " . $stock . ", price = " . $price . " WHERE product_code = \"" . $prod . "\";\n";
}
$mysqli->query($sql);

准备版本相同的 8-9 秒

## Prepare statments
$stmt1 = $mysqli->prepare("UPDATE products SET stock = ?, price = ?, stock_date = now() WHERE product_code = ?;");
$stmt1->bind_param('dds',$stock, $price, $prod);
$stmt2 = $mysqli->prepare("UPDATE products SET stock = ?, price = ? WHERE product_code = ?;");
$stmt2->bind_param('dds', $stock, $price, $prod);

if($stock > 0)
{
    $stmt1->execute();
}
else
{   
    $stmt2->execute();
}

我还尝试在 VPS 中添加一个额外的处理器,它使每秒大约 4 个查询的速度更快。

【问题讨论】:

    标签: php mysql csv mysqli


    【解决方案1】:

    您可以使用 MySQL 的 CSV storage engine 创建一个直接访问您的 CSV 文件的表。无需导入。

    然后,您可以使用 multi-table UPDATE syntax 将 CSV 表直接加入到您的 products 表中,并使用 product_code 列。然后您可以根据从 CSV 表中读取的列更新 products 的列。

    【讨论】:

    • +1 用于 CSV 存储引擎...但是如何将其连接起来。创建表然后换出基础文件?
    • 是的,这行得通。当然,您需要将 CSV 文件放在数据目录下的正确位置,并确保 mysql 用户可以读取/写入。
    • 创建一些索引可能是个好主意,因为我想如果没有它们,性能会很糟糕。
    • 您不能在 CSV 表上创建索引,但是在产品表上拥有正确的索引很重要。例如。我会先尝试对 (product_code, stock) 的索引。
    • 感谢您的回复。目前这有点不合时宜,但我会在未来对此进行研究。
    【解决方案2】:

    关于这个的一些事情......

    1. you can do this with one sql statement 
    UPDATE products 
    SET stock = case new_stock_level when 0 then 0 else new_stock_level end, 
        price = 9.99,
        stock_date = case new_stock_level when 0 then stock_date else now() end
    WHERE product_code = "xxxxxxx";
    
    2. you might want to try wrapping the statements inside of a transaction:
    e.g.
    START TRANSACTION
    UPDATE products ...;
    UPDATE products ...;
    ... ;
    COMMIT TRANSACTION
    

    这两件事应该加快速度。

    【讨论】:

    • 也关于您的原始帖子,如果您正在检查是否存在一行,我会选择 * - 将整个行拖到网络上(如果您的服务器在不同的机器上)。最好只选择一个字段(选择 product_code ...)
    • 在上面,我的意思是说“我不会做选择*”
    【解决方案3】:

    我个人会将更新上传到临时表中,在 product_code 字段上创建一个唯一键,然后像这样运行更新...

    UPDATE tmptable p, products pp 
    SET pp.stock = p.stock,
        pp.price = p.price,
        pp.stock_date = if(p.stock == 0, now(), pp.stock_date)
    WHERE pp.product_code = p.product_code
    

    【讨论】:

      【解决方案4】:

      好的,我知道这不是您问题的直接答案,但我想建议一种不同的方法。

      不要尝试更新整个库存水平,而是尝试仅更新自上次更新以来发生变化的内容?您可以使用某种更改时间来跟踪它。 这在很大程度上取决于您的环境,但可能选择当前股票并将它们与 csv 文件(或相反)进行比较实际上可能比更新每条记录更快。当然,这可能完全是浪费时间,但只有一种方法可以找出...

      【讨论】:

        猜你喜欢
        • 2013-02-28
        • 2011-03-31
        • 2013-12-20
        • 2010-10-16
        • 2021-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多