php - 将新的 XML 数据导入 MySQL 表而不影响现有记录

标签 php mysql xml

我有一个非常大(2.7mb)的 XML 文件,其结构如下:

<?xml version="1.0"?>

<Destinations>

  <Destination>
    <DestinationId>W4R1FG</DestinationId>
    <Country>Pakistan</Country>
    <City>Karachi</City>
    <State>Sindh</State>
  </Destination>

  <Destination>
    <DestinationId>D2C2FV</DestinationId>
    <Country>Turkey</Country>
    <City>Istanbul</City>
    <State>Istanbul</State>
  </Destination>

  <Destination>
    <DestinationId>5TFV3E</DestinationId>
    <Country>Canada</Country>
    <City>Toronto</City>
    <State>Ontario</State>
  </Destination>  

  ... ... ...

</Destinations>

MySQL 表“目的地”如下所示:

+---+--------------+----------+---------+----------+
|id |DestinationId |Country   |City     |State     |
+---+--------------+----------+---------+----------+
|1  |W4R1FG        |Pakistan  |Karachi  |Sindh     |
+---+--------------+----------+---------+----------+
|2  |D2C2FV        |Turkey    |Istanbul |Istanbul  |
+---+--------------+----------+---------+----------+
|3  |5TFV3E        |Canada    |Toronto  |Ontario   |
+---+--------------+----------+---------+----------+
|.  |......        |......    |.......  |.......   |
+---+--------------+----------+---------+----------+

现在我想要处理 XML 并检查 MySQL 表中的每个目标记录。我必须仅将 DestinationId 与每条记录进行比较,并检查它是否存在于我的数据库表中。如果确实存在,则保留该记录并继续,如果不存在,则执行 INSERT 查询将该记录插入该表中。

我首先尝试使用 PHP foreach 循环机制来完成此任务,但由于数据太大,它给我带来了严重的性能和速度问题。然后我想出了这样的 MySQL 过程方法:

DELIMITER $$

USE `destinations`$$

DROP PROCEDURE IF EXISTS `p_import_destinations`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `p_import_destinations`(
    p_xml                     TEXT
)
BEGIN
    DECLARE v_row_index INT UNSIGNED DEFAULT 0;
    DECLARE v_row_count INT UNSIGNED;
    DECLARE v_xpath_row VARCHAR(255);

    -- calculate the number of row elements.
    SET v_row_count := extractValue(p_xml,'count(/Destinations/Destination)');

    -- loop through all the row elements
    WHILE v_row_index < v_row_count DO        
        SET v_row_index := v_row_index + 1;
        SET v_xpath_row := CONCAT('/Destinations/Destination[',v_row_index,']');

    INSERT IGNORE INTO destinations VALUES (
        NULL,
        extractValue(p_xml,CONCAT(v_xpath_row, '/child::DestinationId')),
        extractValue(p_xml,CONCAT(v_xpath_row, '/child::Country')),
        extractValue(p_xml,CONCAT(v_xpath_row, '/child::City')),
        extractValue(p_xml,CONCAT(v_xpath_row, '/child::State'))
    );


    END WHILE;

END$$  

DELIMITER ;

调用此过程的查询:

SET @xml := LOAD_FILE('C:/Users/Muhammad Ali/Desktop/dest.xml'); 
CALL p_import_destinations(@xml);

这非常有效,但我仍然不确定这种方法的可扩展性、性能和速度。此过程中使用的 IGNORE 子句会跳过重复记录,但会累积自动增量键值。就像它正在检查带有 id 3306 的行一样,如果该记录是重复的,它不会将其插入表中(这是一件好事),但会采用自动递增键 3307,下次插入 NON-DUPLICATING 记录时,会将其插入到 3308 处。这看起来不太好。

任何其他方法来满足此类要求将不胜感激。如果我可以继续使用这个解决方案,请指导我?如果不是,为什么?

请记住,我正在处理非常大量的数据。

最佳答案

This worked perfect but I am still not sure about this approach's scalability, performance and speed.

衡量速度,测试其扩展方式。那你就确定了。如果您发现在您的场景中会伤害您的问题,请再次询问,但要使性能/可扩展性问题更加具体。很可能这样的部分已经被问答了。如果不在 Stackoverflow 上,而是在 DBA 网站上:https://dba.stackexchange.com/

And IGNORE clause used in this procedure skips through duplicate record but accumulates the auto increment key value

这也是类似的。如果这些差距对您来说是个问题,这通常表明您的数据库设计存在缺陷,因为这些差距通常毫无意义(比较:How to fill in the "holes" in auto-incremenet fields?)。

但是,这并不意味着其他人也不会遇到这个问题。您可以找到很多相关 Material ,还可以找到如何使用特定版本的数据库服务器来防止这种情况的“技巧”。但老实说,我不会关心差距。约定是标识列具有唯一值。仅此而已。

无论如何,无论是性能还是ID:为什么不把处理分开呢?首先从 XML 导入到导入表中,然后您可以轻松地从该导入表中删除不想导入的每一行,然后可以根据需要插入到目标表中。

关于php - 将新的 XML 数据导入 MySQL 表而不影响现有记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26072707/

相关文章:

mysql用于通过连接获取当前日期的记录

xml - 防止第三方操纵 XML 文件

python - lxml:获取属性值后的字段

php - Solr:计算两个给定日期之间的差异,其中一个值为 *

php - 在 php 中创建独特的民意调查/投票/调查

php - 将逗号分隔值插入 MySQL 表字段

python - 通过 python lxml tree.xpath 解析 xml

php - 将本地存储的文件移动到 amazon S3

php - 单选按钮仅将 1 个值插入 SQL 数据库

MYSQL - 查询获取不同的发送者ID和接收者ID以及richesta_id