【问题标题】:Bind params for the bulk INSERT query? (avoid SQL injections)为批量 INSERT 查询绑定参数? (避免 SQL 注入)
【发布时间】:2013-09-09 14:19:38
【问题描述】:

我想从 Excel 文件中进行一些海量数据库填充。 最经济的方法是使用INSERT INTO 语句,将大量值存储在一个事务中:

INSERT INTO `assortment`(`id`, `sku`, `agroup`, `subgroup`, `title`, `measure_unit`, `price`, `discount`, `imageUrl`, `fileUrl`) 
VALUES ([value-1],[value-2],[value-3],[value-4],[value-5],[value-6],[value-7],[value-8],[value-9],[value-10]), 
([value-1],[value-2],[value-3],[value-4],[value-5],[value-6],[value-7],[value-8],[value-9],[value-10]), 
([value-1],[value-2],[value-3],[value-4],[value-5],[value-6],[value-7],[value-8],[value-9],[value-10]), 
([value-1],[value-2],[value-3],[value-4],[value-5],[value-6],[value-7],[value-8],[value-9],[value-10]), 
...

然而,为了避免 SQL 注入,我希望绑定参数,yii 为此提供了functionality。然而,我似乎不可能为成百上千的价值做到这一点。不是吗?

为了保持 SQL 的健康,我通过 Active Record 属性进行了简单的插入(Yii AR 功能默认清理输入数据):

$auxarr = array();
for ($i = 0; $sheetData[$i]; $i++) 
{
        $model = new Assortment();
        $j = 0; 
            foreach ($labels as $label)
            {
                $auxarr[$label] = $sheetData[$i][$j++];
            }
        $model->attributes = $auxarr;
        if (!$model->save()) 
            throw new CHttpException(400, 'Error db storing');
}

这种方法显然没有时间效率。 有没有什么方法可以在批量 SQL 插入中兼顾安全性和时间效率?

【问题讨论】:

  • 我更喜欢按 1 插入。这样更省时,但有一些因素不允许我使用批量:带索引的大表、对 db 的连续记录(读取)等等。无论如何,我怀疑(或不知道)如何做到这一点,是否可能。
  • 定义“时间无效率”。请在某些数字。
  • 你不能用load data吗?
  • 我没有这些事务的时间效率指标(甚至现在加载 excel 都失败了),我申请的唯一原因是数据库功能的理论知识:1 个事务对多个事务.
  • 批量插入 - 30gb 表上的 1000 条记录需要大约 3 分钟,1by1 大约需要 20 秒。第二 - 在批量表上锁定,在 1by1 上没有。

标签: performance yii sql-injection bulkinsert


【解决方案1】:

Yii 在 CDbCommand 中使用传统的 PDO。 因此,您可以创建一个由这样的系列值组成的字符串

(?,?,?),(?,?,?),(?,?,?),(?,?,?),(?,?,?),(?,?,?)

然后为所有这些占位符创建一个包含值的数组
最后执行所有的东西

【讨论】:

  • 我会尝试应用它。
【解决方案2】:

我的方法是

$sql = "INSERT INTO `assortment`(`id`, `sku`, `agroup`, `subgroup`, `title`, `measure_unit`, `price`, `discount`, `imageUrl`, `fileUrl`) VALUES "

$params = array();
$cntRows = count($sheetData);
for ($i = 0; $i < $cntRows; $i++) 
{

    $j = 0;         
    $rowParams = array();
    foreach ($labels as $label)
    {
        $rowParams[":{$label}_{$i}_{j}"] = $sheetData[$i][$j++];


    }
    $params = array_merge($params, $rowParams);
    $sql . = "(" . implode(",", array_keys($rowParams) ) .")"

}
/*
 Sql now is : INSERT INTO assortment (....) VALUES (  :id_1_1 , sku_1_1 , ... )  (:id_2_1 , sku_2_1 , ...)
 AND $params is { :id_1_1 => [value]  ........ }
*/

$cmd = Yii::app()->db->createCommand($sql);
$cmd->execute($params);

我们在一个事务中执行insert sql,没有多个事务或使用ActiveRecord(浪费内存和执行许多功能)并避免SQL注入。如果您的数据很大,您可以将其拆分为多个事务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-16
    • 2020-11-21
    • 1970-01-01
    • 2018-09-28
    • 1970-01-01
    • 2016-12-09
    • 1970-01-01
    相关资源
    最近更新 更多