我有一个像
Array (
[1] => 85590762,22412382,97998072
[3] => 22412382
Run Code Online (Sandbox Code Playgroud)
)
其中key是item_id,value是我需要针对某项更新的列的值。我可以在循环中使用db_update,但由于性能原因我想避免使用此策略。我想在一个数据库调用中更新所有行。我还认为使用db_query并不是一个好主意。那么,有什么方法可以使用db_update来更新这些行?
根据以上数据,标准的mysql查询将像
update items set sold= 1, users = '85590762,22412382,97998072' Where item_id = 1;
update items set sold = 1, users = '22412382' Where item_id = 3;
Run Code Online (Sandbox Code Playgroud)
不幸的是你不能那样做。当前并且可能在该功能中,将不支持使用一个db_update在具有不同值的不同行上更新(多个)值。
如果您的数据是这样的:
$for_update = array(
1 => "85590762,22412382,97998072",
3 => "22412382",
);
Run Code Online (Sandbox Code Playgroud)
您可以执行以下操作:
foreach ($for_update as $key => $value) {
$fields = array('sold' => 1, 'users' => $value);
db_update('items')->fields($fields)->condition('item_id', $key, '=')->execute();
}
Run Code Online (Sandbox Code Playgroud)
优点:其他模块可以挂接到您的查询中,可以支持多个数据库驱动程序
缺点:对象初始化很慢,数据库连接/流量很多
...,因为在这种情况下,没有对象实例化/操作,这会带来一些昂贵的转换。(即:https : //drupal.stackexchange.com/questions/129669/whats-faster-db-query-db-select-or-entityfieldquery)
foreach ($for_update as $key => $value) {
db_query("UPDATE items SET sold = :sold, users = :users WHERE item_id = :item_id",
array(':sold' => 1, ':users' => $value, ':item_id' => $key)
);
}
Run Code Online (Sandbox Code Playgroud)
优点:没有对象初始化和操作<,因此更快。
缺点:其他模块无法挂接到您的查询中,您的代码可能在不同的数据库驱动程序下中断,大量的数据库连接/通信
在某些情况下,这可以提高您的性能。
$transaction = db_transaction();
try {
foreach ($for_update as $key => $value) {
$fields = array('sold' => 1, 'users' => $value);
db_update('items')->fields($fields)->condition('item_id', $key, '=')->execute();
}
}
catch (Exception $e) {
$transaction->rollback();
watchdog_exception('my_type', $e);
}
Run Code Online (Sandbox Code Playgroud)
注意:交易多用,需要什么或什么都不需要时。但是,使用某些数据库驱动程序,您可以优化COMMIT命令。
在情况1中,您得到的是这样的:
UPDATE items SET sold = 1, users = '85590762,22412382,97998072' WHERE item_id = 1;
COMMIT;
UPDATE items SET sold = 1, users = '22412382' WHERE item_id = 3;
COMMIT;
Run Code Online (Sandbox Code Playgroud)
通过事务,您可以执行以下操作:
UPDATE items SET sold = 1, users = '85590762,22412382,97998072' WHERE item_id = 1;
UPDATE items SET sold = 1, users = '22412382' WHERE item_id = 3;
COMMIT;
Run Code Online (Sandbox Code Playgroud)
使用COMMIT,您可以将数据写到最终位置(到长期存储中,直到此为止,它仅在内存中的某个位置或临时位置)。使用回滚时,将删除这些更改。至少我是这样理解的。(即,当我使用sqlite时,它的性能得到了改善。)
与情况1或2 +相同
:优点:如果需要保持一致,可以回滚数据,仅将数据写出一次到驱动器<因此,仅sql“一次”执行IO,大量数据库连接/流量
$ids = array();
$when_then = "";
foreach ($for_update as $key => $value) {
$ids[] = $key;
$when_then .= "WHEN $key THEN '$value' ";
}
db_query("UPDATE items
SET sold = 1, users = CASE item_id
$when_then
ELSE users
END
WHERE item_id IN(:item_ids)", array(':item_ids' => $ids));
Run Code Online (Sandbox Code Playgroud)
从这里开始,这可能是最快的方法。
注意:$when_then变量没有最好的解决方案,最好是可以使用参数,或者转义不安全的数据。
优点:服务器和sql之间只有一个请求,冗余数据更少,一个大的sql查询要快得多,然后是许多小的sql
缺点:其他模块无法挂接到您的查询中,您的代码可以在不同的数据库驱动程序下中断
还请注意,在(我认为)PHP 5.3之后,默认情况下,您不能在db_query或PDO中运行多个语句,因为它可以是SQL注入,因此会阻塞。但是,您可以设置此项,但不建议这样做。(PDO支持多个查询(PDO_MYSQL,PDO_MYSQLND))
13-05-2019编辑:
附带一提,我几个月前对中型数据集进行了一些性能测量,以通过db_select和查询一些数据db_query。这些性能的大小是:在运行一次时db_select,可以运行两个db_query。这也适用于db_update和db_query。该测试查询了一些简单SELECT,没有JOINS,没有花哨的花哨的东西,只有两个条件的列。当然,该度量还包含/包括建立这些查询所需的时间(在两种情况下)。但是请注意,Drupal的编码标准要求使用db_update,db_delete,db_merge在修改时通常,只有“允许” db_query,而不是db_select操作。
| 归档时间: |
|
| 查看次数: |
3596 次 |
| 最近记录: |