如何提高mysql LOAD XML LOCAL INFILE表导入的性能?

时间:2017-06-30 09:34:22

标签: mysql xml performance import load-data-infile

对于mysql数据库,我有一些XML转储文件。

pricing表的一个表导入文件如下所示:

<database>
    <table>
        <row>
            <id>5954017</id>
            <foo>narf</foo>
            <bar_id>1377</bar_id>
            <price_single>800.00</price_single>
            <price_double>1500.00</price_double>
            <price_triple>2000.00</price_triple>
            <price_quad>1900.00</price_quad>
            <currency>USD</currency>
        </row>
        ...
    </table>
</database>

它有

$ xmllint --xpath "count(//row)" import.xml 
223198

行及其大小为:

du -h import.xml 
69M import.xml

我想通过mysql&#39; LOAD XML功能导入。该表将始终被截断。

MySQL [my_database]> LOAD XML LOCAL INFILE 'import.xml' INTO TABLE pricing ROWS IDENTIFIED BY '<row>' \G

它成功了,但表导入似乎需要相当长的时间:

Query OK, 223198 rows affected (1 hour 44 min 48.40 sec)
Records: 223198  Deleted: 0  Skipped: 0  Warnings: 0

我读到人们正在使用此LOAD INFILE功能导入千兆字节的数据,我预计其性能会在几分钟而非几小时的范围内快得多。我的期望是错的吗?这是200,000个条目的数据集的正常时间吗?

(我也将这个速度与自定义的php导入脚本进行比较,该脚本手动解析XML并逐行插入每一行;并且所有表的任务需要45分钟。我希望LOAD XML LOCAL INFILE能够胜出那个任务。)

我的表格如下:

MySQL [my_database]> DESCRIBE pricing;
+----------------+--------------+------+-----+---------+-------+
| Field          | Type         | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| id             | int(11)      | NO   | PRI | NULL    |       |
| foo            | varchar(256) | YES  |     | NULL    |       |
| bar_id         | int(11)      | YES  |     | NULL    |       |
| price_single   | float        | YES  |     | NULL    |       |
| price_double   | float        | YES  |     | NULL    |       |
| price_triple   | float        | YES  |     | NULL    |       |
| price_quad     | float        | YES  |     | NULL    |       |
| currency       | varchar(3)   | YES  |     | NULL    |       |
+----------------+--------------+------+-----+---------+-------+

通过以下方式创建:

DROP TABLE IF EXISTS `pricing`;
CREATE TABLE `pricing` (
      `id` int(11) NOT NULL,
      `foo` varchar(256) DEFAULT NULL,
      `bar_id` int(11) DEFAULT NULL,
      `price_single` float DEFAULT NULL,
      `price_double` float DEFAULT NULL,
      `price_triple` float DEFAULT NULL,
      `price_quad` float DEFAULT NULL,
      `currency` varchar(3) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
      PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

我可以做些什么来改善LOAD XML LOCAL INFILE的性能?

1 个答案:

答案 0 :(得分:0)

将您的XML转换为CSV文件,使得导入几乎是即时的。

您可以使用例如xslt转换XML xsltproc

 $ xsltproc transformToCsv.xsl price.xml > price.csv
 "5954017"╡"narf"╡"1377"╡"800.00"╡"1500.00"╡"2000.00"╡"1900.00"╡"USD"

适当的xslt transformToCsv.xsl如下所示:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"
                encoding="utf-8"/>

    <xsl:param name="delim"
               select="'╡'"/>
    <xsl:param name="quote"
               select="'&quot;'"/>
    <xsl:param name="break"
               select="'&#10;'"/>

    <xsl:template match="/">
        <xsl:apply-templates select="database/table/row"/>
    </xsl:template>

    <xsl:template match="row">
        <xsl:apply-templates/>
        <xsl:if test="following-sibling::*">
            <xsl:value-of select="$break"/>
        </xsl:if>
    </xsl:template>

    <xsl:template match="*">
        <xsl:value-of select="concat($quote, normalize-space(), $quote)"/>
        <xsl:if test="following-sibling::*">
            <xsl:value-of select="$delim"/>
        </xsl:if>
    </xsl:template>

    <xsl:template match="text()"/>
</xsl:stylesheet>

然后导入语法将更改为:

$ mysql \
    -h YOUR_MYSQL_HOST \
    -P YOUR_PORT \
    -uYOUR_USER \
    -pYOUR_PASSWORD \
    YOUR_DATABASE \
    -e "LOAD DATA LOCAL INFILE 'pricing.csv' INTO TABLE pricing FIELDS TERMINATED BY '╡' ENCLOSED BY '\"' \G"

导入200,000个条目变为(毫秒)。