首页 > 解决方案 > 为什么我在导入 XML 时会出现重复项?

问题描述

我花了半天时间才明​​白,我不知道该怎么办。我有一个 XML 文件,其中包含 146 565 条名称和类记录以及导入 XML

    public function parse() {
        $start = microtime(true);
        $q = 1;        
        while ($this->reader->read() && $this->reader->name !== 'licenses');
        while ($this->reader->localName === 'licenses') {
            $node = simplexml_import_dom($this->doc->importNode($this->reader->expand(), true));
            $inn = (string) $node->inn;
            $name = (string) $node->name;            
            $this->service->create($name, $inn);
        }
        echo 'Time script: ' . round(microtime(true) - $start, 4) . ' sec.';
    }

当我使用它echo $name代替它时,$this->service->create($name, $inn);它工作正常。我的屏幕上有 146 565 个名字。但是当我将它与我的服务一起添加到 MySql 中时,脚本并没有停止。当我将一个包含 1000 行的测试文件导入到数据库中时。

MariaDB [dbbase]> SELECT COUNT(1) FROM names_table;
+----------+
| COUNT(1) |
+----------+
|   248778 |

我的服务

public function create(string $name, string $inn): bool {

        try {
            $this->sth->execute([
            ':uuid' => Uuid::uuid4(),
            ':name' => $name,
            ':inn' => $inn
        ]); 
        return true;
        } catch (RuntimeException $e) {
            die($e->getMessage());
        }
    }

如何解决?我明白服务有问题,但我不知道该怎么办。我尝试不return true带它和带它 - 脚本不会停止。PS 添加了 id (primary, auto_increment) 而不是 uuid - 结果相同。

标签: phpxml-parsing

解决方案


首先将处理分为两部分:

public function parse() {
        $start = microtime(true);
        $q = 1;        
        while ($this->reader->read() && $this->reader->name !== 'licenses');
        $pairs = [ ];
        while ($this->reader->localName === 'licenses') {
            $node = simplexml_import_dom($this->doc->importNode($this->reader->expand(), true));
            $pairs[] = [ (string) $node->name, (string) $node->inn, Uuid::uuid4() ];
        }
        echo 'Time script: ' . round(microtime(true) - $start, 4) . ' sec.';

        foreach ($pairs as $pair) {
            list($name, $inn, $uuid) = $pair;
            print date('H:i:s') . " inserting {$name}\n";
            $this->service->create($name, $inn, $uuid);
        }

        echo 'Time script: ' . round(microtime(true) - $start, 4) . ' sec.';
    }

如果问题是插入时间太长,您可以通过两个准备好的语句来更改查询策略,一个有 200 对,一个有一个,这样您就可以用一个 INSERT 插入多行。这应该可以很好地加速事情的发展。否则,还有可怕的解决方案:-)。

请注意,上面我已将 UUIDv4 创建卸载到第一个周期,这需要您将服务创建调用更改为从参数中读取 uuid。这是因为我曾经在使用 PHP 函数时遇到了一个漂亮的错误,random_bytes()如果随机性的来源(可能已经/dev/urandom但实际上以某种方式被/dev/random耗尽了)会阻塞系统。

如果修改后的代码在第一个循环中阻塞(甚至在任何 SQL 代码被调用之前),那么就是你的 UUIDv4 调用有缺陷,我们可以看看修复它。


推荐阅读