我目前正在将一个非常大的(至少是我的新手经验中最大的数据库)数据迁移到另一个结构中。
事实上,我正在尝试将数据从一个非常古老的重型SMF数据库迁移到Flarum,我将其作为学习步骤。
现在我为所有帖子中的所有用户提供了特定于SMF的用户ID,现在我想将帖子迁移到Flarum。但问题是SMF用户ID与Flarum用户ID不同。 Flarum数据库中的属性由AUTO_INCREMENT
属性创建,因此不相同。
因此,为了翻译所有帖子,我正在使用这个正常工作的天真循环,现在正在考虑优化它。
while ($topic = $topics->fetch())
{
$posts = $db->query("SELECT * FROM smf_posts WHERE ID_TOPIC = @{$topic->ID_TOPIC}");
$posts->setFetchMode(PDO::FETCH_OBJ);
while ($post = $posts->fetch())
{
$user = $db2->query("SELECT id FROM flarum_users WHERE user_name = @{$post->posterName}");
$user = $user->fetch();
// Now insert the post
}
// Now insert the topic into discussions
}
现在,在我获得的数据集中共有36,194个主题,这次迁移在我的机器上花费了大约30分钟。
我知道我必须在单个查询中获取大量数据以使其更快,但我只是没有看到它如何。我最初想过加入这两个表,但它们位于不同的数据库中,在我的情况下更糟糕的是,它们位于不同的服务器中。
我该怎么做?
答案 0 :(得分:1)
首先,我想评论是否值得优化您只需要执行一次的任务。开发改进需要30多分钟吗?如果是这样,那就不要打扰了。只需在30分钟内运行并称之为成功。除非您需要多次运行此迁移。那么也许值得改进它。
flarum中有多少用户?可能不会超过几千。您可以通过在开始处理主题之前执行一个查询来消除重复的内部查询,并在PHP关联数组中保存username-to-id映射。
$userQuery = $db2->query("SELECT id, user_name FROM flarum_users");
$userData = $userQuery->fetchAll(PDO::FETCH_OBJ);
$userMap = [];
foreach ($userData as $user) {
$userMap[$user->user_name] = $user->id;
}
// then start processing topics
在循环内部,您可以使用$userMap
更快地将用户名更改为id - 只是关联数组查找而不是运行另一个SQL查询。
while ($post = $posts->fetch())
{
$userId = $userMap[$post->posterName]; // no SQL query
// insert post
}
通常,此技术称为Loop-Invariant Code Motion。如果你有一个在循环中运行的代码,但无论你运行多少次,结果都知道它是相同的,为什么在循环中呢?在循环之前执行一次,并将结果保存在某个变量中。
我也同意@Ben上面的评论:确保smf_posts.ID_TOPIC
的数据库表上有一个索引,以便更快地选择帖子。