mysql update 几万 非常慢_mysql进行update操作速度慢,如何解决

PHP 默认是同步无并发请求操作,如果使用 for 循环更新数据效率很慢,正常每秒处理 30 条 SQL 语句,对于几百万数据来说简直是灾难。而改造后速度在每秒 200 条更新数据。

旧版逻辑

$mysql = new \Tool\MysqlQuery();

$sql = "SELECT count(*) FROM `big_data` where 1";

$count = $mysql->getOne($sql);

$limit = 1000;

$start = time();

for ($i = 1; $i < ($count / $limit) + 1; $i++) {

$sql = "SELECT * FROM `big_data` where 1 limit ".(($i-1)*$limit).', '.$limit;

echo $sql.PHP_EOL;

$avgs = $mysql->getAll($sql);

foreach ($avgs as $avg) {

$sql1 = "UPDATE `big_data` SET mobile = '".readSafeData($avg['mobile'])."' where id = {$avg['id']}";

$rs = $mysql->query($sql1);

if (!$rs) {

echo 'Error: '.$sql1.PHP_EOL;

}

// var_dump($rs);

usleep(10000);

}

}

$end = time();

$time = $end - $start;

echo 'Finish ! Cost '.$time.' S '.PHP_EOL;

改造批量处理

/**

* MySQL 大数据批量更新操作

*

* User: lisgroup

* Date: 2019-01-22

* Time: 16:03

*/

/**

* 生成最终 SQL 类似结构:

*

* UPDATE `big_data` SET

* realname = CASE id

* WHEN 1 THEN 'val1'

* WHEN 2 THEN 'val2'

* WHEN 3 THEN 'val3'

* END,

* idcard = CASE id

* WHEN 1 THEN 'val1'

* WHEN 2 THEN 'val2'

* WHEN 3 THEN 'val3'

* END,

* mobile = CASE id

* WHEN 1 THEN 'val1'

* WHEN 2 THEN 'val2'

* WHEN 3 THEN 'val3'

* END

* WHERE id IN (1, 2, 3)

*/

require_once __DIR__.'/../Application.php';

$config = ['DB_HOST' => 'localhost', 'DB_PORT' => '3306', 'DB_USER' => 'root', 'DB_PASS' => 'root', 'DB_NAME' => 'test', 'DB_CHARSET' => 'utf8'];

$mysql = new \Tool\MysqlQuery($config);

$sql = "SELECT count(*) FROM `big_data` limit 1000";

$count = $mysql->getOne($sql);

// $count = 10000;

$limit = 1000;

$start = time();

for ($i = 1; $i < ($count / $limit) + 1; $i++) {

$sql = "SELECT * FROM `big_data` limit ".(($i - 1) * $limit).', '.$limit;

echo $sql.PHP_EOL;

$avgs = $mysql->getAll($sql);

// 数据拼接

$ids = '';

// 批量更新 sql 语句

$sql = "UPDATE `big_data` SET ";

$sql_name = ' realname = CASE id ';

$sql_idcard = ' idcard = CASE id ';

$sql_mobile = ' mobile = CASE id ';

foreach ($avgs as $avgValue) {

$sql_name .= sprintf("WHEN %d THEN '%s' ", $avgValue['id'], randData($avgValue['realname']));

$sql_idcard .= sprintf("WHEN %d THEN '%s' ", $avgValue['id'], randData($avgValue['idcard']));

$sql_mobile .= sprintf("WHEN %d THEN '%s' ", $avgValue['id'], randData($avgValue['mobile']));

// 1. 拼接 where 条件

$ids .= $avgValue['id'].',';

}

$sql = $sql.$sql_name.' END, '.$sql_idcard.' END, '.$sql_mobile.' END';

$ids = rtrim($ids, ',');

// 拼接条件

$sql .= " WHERE id IN ({$ids})";

$res = $mysql->query($sql);

if(!$res) {

echo $sql.PHP_EOL;

}

}

$end = time();

$time = $end - $start;

$min = floor($time / 60);

$second = $time % 60;

echo 'Finish ! Cost '.$min.':'.$second.' S '.PHP_EOL;

function randData($data)

{

return hash('sha256', md5($data)).mt_rand(0, 9);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL执行update语句报锁等待超时常见于并发操作时,多个事务同时试图访问同一数据行造成的冲突。当多个事务同时操作相同的数据时,其中一个事务持有锁,而其他事务等待锁的释放。如果等待时间超过了设置的锁等待超时时间,就会报出锁等待超时错误。 解决这个问题的方法有几种: 1. 优化查询语句和事务:可以通过修改SQL语句,减少对数据行的访问,减少锁竞争的可能性。同时,可以考虑将事务拆分成更小的操作,减少锁的持有时间。 2. 提高锁粒度:可以通过使用更大颗粒度的锁来减少并发冲突。比如,使用表级锁代替行级锁,或者使用读写锁来提高并发性能。 3. 调整隔离级别:可以将事务的隔离级别调整为较低的级别,如读已提交或快照隔离。这样可以降低锁的粒度,减少锁竞争。 4. 增加服务器资源:锁等待超时的原因可能是服务器资源不足,可以考虑增加服务器的内存、CPU等资源,提高服务器的性能。 5. 使用悲观锁或乐观锁:可以使用悲观锁或乐观锁来控制并发访问。悲观锁使用锁机制阻止其他事务访问数据,而乐观锁则通过版本号或时间戳等机制来判断数据是否被其他事务修改。 总之,MySQL执行update语句报锁等待超时是由于多个事务之间的并发冲突导致的。通过优化查询语句和事务、提高锁粒度、调整隔离级别、增加服务器资源以及使用悲观锁或乐观锁等方法,可以解决这个问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值