2017-06-30 39 views
0

對於mysql數據庫,我有一些XML轉儲文件。如何提高mysql LOAD XML LOCAL INFILE表導入的性能?

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的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 

我讀,人們正在導入千兆字節的數據與此負載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

+0

不要使用XML

+0

@RickJames我害怕有人這樣說。 – k0pernikus

+0

我知道很多數據源被鎖定到XML中。後來的兩個'標準'非常友好:JSON和YAML。但即使這些需要一些解析時間(儘管可能更少)。另一個問題:應該使用InnoDB來代替MyISAM。 –

回答

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" 

導入20萬項變成(毫)秒的事。