我对此很陌生,但下面的代码运行得很好,它提取json,循环并将其插入数据库,同时检查玩家是否存在,如果存在,则更新ONLY分数和奖金。如果是新玩家,则插入新行。
我的问题是,我的玩家列表在10-15K左右(玩家1到15000)。当我监视Laravel查询日志以查找潜在的性能问题时,我注意到由于foreach逐个循环查询,所以运行的查询量非常大。
由于所有10-15K的数据都在那里,并且可以从$scores变量中获得。有没有什么方法可以让它运行一个大查询,而不是10-15K个单独的查询,同时受到PDO占位符的保护?
我想用PHP构建一个数组,然后将该数组提供给Mysql查询,但接下来如何使用占位符来保护它呢?此外,每天会运行几次
我真的很困惑如何最好地做到这一点,所以这是代码,原始代码要大得多,因为它包含团队、位置、ip地址等等。但这是一个精简的示例
Unique key in database set as (id)
$scores = '
{
"1":{
"id":"1",
"player":"1",
"name":"James",
"score":"10.25",
"bonus":"2.10"
},
"2":{
"id":"2",
"player":"2",
"name":"John",
"score":"11.50",
"bonus":"1.10"
}
}';
$decoded = json_decode($scores);
foreach($decoded AS $value)
{
$update = DB::insert("INSERT INTO players (id,player,name,score,bonus) VALUES (:id,:player,:name,:score,:bonus)
ON DUPLICATE KEY UPDATE score=VALUES(score), bonus=VALUES(bonus)",
array(
':id' => ,$value->id
':player' => ,$value->player
':name' => ,$value->name
':score' => ,$value->score
':bonus' => ,$value->bonus
)
);
}
首先,您的INSERT可以如下所示:
INSERT INTO table_name(col1, col2) VALUES(val1, val2), (val1, val2)
这是一个插入2行的INSERT,它比2个INSERTs 更快
对于laravel,您可以使用此处所示的插入函数(请参阅"将多个记录插入表")
不确定它在幕后是如何工作的,我猜它比foreach 快
这里有一种非常快速的方法(除了IODKU循环或它的@Basic批处理)。
- 将
INSERT
所有数据批处理到临时表中。(一个la@Traxo的回答。) - 复制"新行":
INSERT INTO real SELECT ... FROM tmp LEFT JOIN real ON ... WHERE ... IS NULL
- 更新现有行:
UPDATE real JOIN tmp ON ... SET real.bonus = tmp.bonus, real.score = bonus.score;
有一些细节,例如BEGIN
。。。COMMIT
假设您正在使用InnoDB(您应该使用)。
如果你的定期更新真的是完全替换,那么就这样做:
CREATE TABLE new LIKE real;
- 加载
new
RENAME TABLE real TO old, new TO real;
——原子和瞬时DROP TABLE old;