php - 使用 ZF2 和 Doctrine2 将 SQL Server 表转换为 MySQL

标签 php mysql zend-framework doctrine-orm

我为我的一位客户开发了一个应用程序。他已经有了一个。所以我需要将他的实际数据库(SQL Server)转换为新的(MySQL)。

SQL Server 的某些表有超过 10.000.000 条记录。当我开始开发这个转换器时,我从一些带有几条记录的表开始,所以我找到了所有记录并保存到我的新 MySQL 数据库中。我将向您展示一些代码以更好地理解(这只是一个示例)

<?php

namespace Converter\Model;

class PostConverter extends AbstractConverter 
{

    public function convert() 
    {
        // this is the default connection, it is a mysql database (new application)
        $em = $this->getEntityManager();
        // this return an alternative connection to the sqlserver database (actual application)
        $emAlternative = $this->getEntityManagerAlternative();

        // instance of Converter\Repository\Post
        $repository = $emAlternative->getRepository('Converter\Entity\Post');

        $posts = $repository->findAll();

        foreach ($posts as $post)
            $post = new Post();
            $post->setTitle($object->getTitle());
            $em->persist($post);
        }  

        $em->flush();
    }
}

现在让我们假设 Post 表有超过 10.000.000 条记录。我不能只是找到所有并对其进行迭代。我会离开内存。所以我做了这样的事情。

存储库类:

<?php

namespace Converter\Repository;

class Posts extends \Doctrine\ORM\EntityRepository
{

    public function findPosts($limit, $offset)
    {
        $qb = $this->createQueryBuilder('Post');

        $qb->setMaxResults($limit);
        $qb->setFirstResult($offset);

        return $qb->getQuery->getResult();
    }
}

在这里,我在 while 循环中一次只找到几篇文章。但它有点慢。我找不到更好的解决方案来提高性能

<?php

namespace Converter\Model;

class PostConverter extends AbstractConverter 
{

    public function convert() 
    {
        $em = $this->getEntityManager();
        $emAlternative = $this->getEntityManagerAlternative();

        $repository = $emAlternative->getRepository('Converter\Entity\Post');

        $limit = 1000;

        while ($object = $repository->findPosts($limit, $offset) {
            $post = new Post();
            $post->setTitle($object->getTitle());
            $em->persist($post);

            $offset += $limit;
        }  

        $em->flush();
    }
}

我以前从未做过这样的事情。也许我走错路了。如果你们中的一些人能告诉我正确的,我将不胜感激,这样我就可以继续前进了。

谢谢大家


编辑

我不能把一个转给另一个。我在这里发布的只是一个示例,在转换中我必须在插入新数据库之前处理几乎所有数据。他的实际应用是在2005年开发的。数据库甚至没有规范化

最佳答案

我目前正在构建一个存在类似问题的数据仓库系统。 Doctrine's own documentation正确地说:

An ORM tool is not primarily well-suited for mass inserts, updates or deletions. Every RDBMS has its own, most effective way of dealing with such operations and if the options outlined below are not sufficient for your purposes we recommend you use the tools for your particular RDBMS for these bulk operations.

这就是我的处理方式:

  • 使用 Doctrine 的工具创建您的空 MySQL 数据库。
  • 列出 MySQL 数据库中的所有索引和主键并删除它们。我会编写这个脚本。这将消除持续索引更新的开销,直到您的数据迁移完成。
  • 编写脚本来复制数据。以几千个批处理循环遍历 SQL Server 数据并插入 MySQL。
    • 使用 PDO 或原生库。没有教义或查询构建器。手写查询。
    • 打开一个到 SQL Server 的连接和一个到 MySQL 的连接。在脚本执行期间让它们保持打开状态。
    • 使用LIMIT和主键> last id批量查询。使用 OFFSET 查询通常较慢。
    • 在循环之外准备语句以优化查询处理。
    • 将每批插入包装在一个事务中以减少事务开销。
    • 如有必要,“手动”检查参照完整性。您的表还没有主键。
    • 如果您有很多表,请将代码分段为对象或函数,以便可以从内存中清除局部变量,从而更容易调试。
    • 您可能想调用 gc_collect_cycles()定期。如果您的代码被分解为对象,这是一种控制内存的简单方法。
  • 重新创建数据库索引和主键。如果这些是从一开始就编写好的,则可以加分。注意任何因重复数据错误而无法创建的主键。
  • 在将新的 MySQL 数据库投入生产之前进行测试和测试。您不想稍后再编写脚本来修复数据迁移。

关于php - 使用 ZF2 和 Doctrine2 将 SQL Server 表转换为 MySQL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36143948/

相关文章:

PHP:用于错误处理的现代版本 "or die();"

session - 如果不在 session 中(如果他没有登录),如何在 Zend Framework 2 中配置 Module.php 以重定向用户?

php - 如何在 Zend Framework 中使用 PHPUnit 测试变量

php - 语法错误,意外的 T_ECHO,在第 110 行的/Secured_Page_Edit.php 中需要 ',' 或 ';'

PHP 无法加载动态库 "libMagickWand"

c# - 实现一种有效的机制,在删除前检查一条记录是否被其他表引用

mysql - 在 Hibernate 中使用注解映射表的问题

php - 将 sql 变量传递给 PHP 变量,然后返回给 sql 语句

php - 如何使用多种表单提交唯一数据 PHP/MySQL

php - Zend Validate - 多个值