为了账号安全,请及时绑定邮箱和手机立即绑定

将大量记录插入有关系且没有重复的数据库

将大量记录插入有关系且没有重复的数据库

PHP
偶然的你 2021-11-13 10:40:03
我从第 3 方获得了一些记录(大约 30k),其结构与此类似(所有字符串):first_name, last_name, city另外我在 MySQL 中有 2 个表:用户和城市(大约 25k 条记录)。users 表有一个到城市表的外键。我需要users用来自 api 的记录和citites表的外键来填充表。如果城市不存在,我需要创建它。所以我的代码是这样的:<?php$users = $api->getUsers();$existingUsers = $this->userRepository->getIds();$existingCities = $this->cityRepository->geIdsIndexedByName();$db->beginTransaction();foreach ($users as $i => $user) {  // if no city with such name, then create new and insert to array  if (!array_key_exists($user['city'], $existingCities) {     $cityId = $db->insert('cities', ['name' => $user['city']]);    $existingCities[$user['city_id']] = $cityId;  }  $user['city_id'] = $existingCities[$user['city']];  if (in_array($user['id'], $existingUsers) { // if record with such id exists, then we update it      $db->update('users', $user);  } else {      $db->insert('users', $user);  }  if (($i % 100) === 0) { // use transactions to avoid mass inserts and updates    $db->commit();    $db->beginTransaction();  }}我不喜欢的是,我必须将所有城市和所有用户加载到内存中以检查记录是否已经存在。我这里不使用 ORM,没有对象,只有很小的数组,但它仍然会占用资源,我想减少内存消耗。是否有任何实践可以优化该过程?我有一个想法,将 NoSQL 存储用作现有用户和引用的缓存,但这是不允许的。
查看完整描述

1 回答

?
MM们

TA贡献1886条经验 获得超2个赞

如果我理解正确,为了将新列表与旧列表匹配,您将必须匹配城市名称。虽然这并不理想,但它可能是唯一可用的解决方案。


如果您的城市名称是唯一的,那没问题。但如果它们不是唯一的(Springfield AK、Springfield CA、Springfield CO、Springfield GA、Springfield ID、Springfield IL、Springfield IN 等),您将需要更多信息来匹配。此外,拼写错误(springfield vs springfiled)将破坏您规范化数据库的原因......


第一步,将新信息添加到新表中。我将其称为新信息...


newinfo

----------

first_name

last_name

city

因此假设城市名称是唯一的,下一步是将所有新的唯一城市名称添加到cities. 如果你有一个唯一的索引cities.name,你可以简单地


insert ignore into cities('name') select city from newinfo  

否则,您必须加入表以查找新值:


insert into cities ('name') 

select newinfo.city 

from newinfo 

left join cities on newinfo.city=cities.name 

where cities.name is null

现在您的cities表中有所有可能的城市,您需要插入所有新名称。考虑如何获取需要插入的信息:


select newinfo.first_name, new info.last_name, cities.id 

from newinfo 

inner join cities on new info.city=cities.name

然后,当您对获得正确的数据感到满意时,插入它:


insert into users 

values('first_name','last_name','city_id') 

select newinfo.first_name, new info.last_name, cities.id 

from newinfo 

inner join cities on new info.city=cities.name 

现在您已经完成了表 newinfo 并且可以将其删除。


查看完整回答
反对 回复 2021-11-13
  • 1 回答
  • 0 关注
  • 167 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信