【问题标题】:Optimize MySQL table to tables import优化 MySQL 表到表导入
【发布时间】:2009-06-10 20:12:32
【问题描述】:

我编写了一个导入器,它将数据从平面表复制到其他几个表中,并通过给定的 XML 映射它们。这是针对商店数据库的,其中每个产品可以有多个属性,每个属性可以有几种不同的语言,这意味着它可以很快地汇总大量数据。

目前有超过 50,000 行。我当前的导入代码如下所示:

string query = "SELECT * FROM " + tableDataProducts + " ORDER BY "
            + productIdField;

        DataSet importData = new DataSet();
        Hashtable data = new Hashtable();

        db.DoSelectQuery(query, ref importData, tableDataProducts);

        foreach (DataRow row in importData.Tables[0].Rows) {
            foreach (MapEntry e in mapping[tableObjPropertyValue]) {
                string value = row[e.ImportXmlAttributeName].ToString();

                if (value.Equals("null",
                            StringComparison.OrdinalIgnoreCase)
                        || value.Length < 1)
                    continue;

                data.Clear();

                data.Add("ProductSN", productIdToSn[row[
                    productIdField].ToString()]);
                data.Add("ObjPropertyGroupID", "0");
                data.Add("ObjPropertyID", e.ObjPropertyID);
                data.Add("LanguageID", e.LanguageID);
                data.Add("Value", value);

                db.DoPreparedInsertQuery(tableObjPropertyValue, data);
            }
        }

可以看出,我首先从平面导入表中读取数据,然后遍历代表单个产品的每一行,对于每个产品,我遍历属性映射并将每个属性复制到名为 data 的 Hashtable 中。 null 值被跳过。

将所有列复制到哈希表后,我插入行。

目前,此方法每分钟仅处理大约 700 行,这导致此导入需要大约一小时。我该如何优化它?

[编辑]

这是 XML 的简化版本,因为实际的 XML 太大而无法在此处显示:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<DATAPACKET Version="2.0">
<METADATA>  
<FIELDS>
   <FIELD FieldName="source_id" DisplayLabel="source_id" FieldType="String" FieldClass="TField"/>
   <FIELD FieldName="data_field" DisplayLabel="data_field" FieldType="Unknown" FieldClass="TField"/>
</FIELDS>
</METADATA>
<ROWDATA>
   <ROW source_id="data_1" data_field="some string"/>
   <ROW source_id="data_2" data_field="another string"/>
</ROWDATA>
</DATAPACKET>

此 XML 被导入到单个表中,每个字段都成为一列。有一个映射 XML,如下所示:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<DATAPACKET Version="2.0">
<METADATA>  
<FIELDS>
   <FIELD FieldName="source_id" DisplayLabel="source_id" FieldType="String" FieldClass="TField"/>
   <FIELD FieldName="target" DisplayLabel="target" FieldType="Unknown" FieldClass="TField"/>
</FIELDS>
</METADATA>
<ROWDATA>
   <ROW source_id="data_1" target="products::id"/>
   <ROW source_id="data_2" target="products::name"/>
</ROWDATA>
</DATAPACKET>

目标属性包含目标表和列,格式如下:target='table::column'

【问题讨论】:

    标签: c# mysql optimization import


    【解决方案1】:

    SQL 中的批量操作速度快如闪电。如果您可以将您的 XML 文档转换为一系列 SQL 查询,那将大大提高性能。

    编辑:我不明白您要做什么,但在我看来,您从一张扁平的桌子开始,然后以一堆其他桌子结束。为什么不这样做:

    insert into Product
    (id, name)
    select source_id, data_field
    from FlatTable
    

    这是相当快的,但其代价是不如 XML 映射灵活。

    【讨论】:

    • 我添加了一个简化的 XML 示例。
    • 您能添加一个简化的“平面”表行吗? “data_1”标签是否有特殊含义,例如“data_1”是否对应“source_id”,因为source_id是第一个字段?
    • 平面表对于第一个 xml 的每个字段都有一行。 (在这种情况下,它有“source_id”和“data_field”列)。映射使用 source_id 来标识平面表中的列。获取此列并将其“data_field”值复制到目标(保存映射的表和列信息)。
    • 唉,这是不可能的,因为存在一些依赖关系(例如,ObjPropertyValue 需要一个 ObjPropertyID,它是在填充表 ObjProperty 时自动生成的。我的程序确实与这些相关)并且需要修改其他值(一些ID 是通过连接其他 ID 生成的)或在导入时检测并插入(基于文件扩展名的 MimeType)。
    【解决方案2】:

    好的,有两件事:首先,我将每行插入的方法更改为缓存大约 1000 行并使用单个 MySQL 插入插入它们(请参阅multiple inserts)。

    其次,可能也是最重要的一点,我每个产品都有很多重复项,这些重复项累积成一个大的、血腥的混乱,需要 1 小时才能导入。在导入之前消除这些重复项后,我将执行相同操作的时间缩短到 10 秒...

    在导入之前应该检查他的选择结果是否有重复项。在这种情况下,我想选择每个产品一次,但我选择了每种语言版本的每个产品。 (意思是我有 4 个基本相同的产品,只是用另一种语言)

    【讨论】:

      猜你喜欢
      • 2011-02-11
      • 1970-01-01
      • 1970-01-01
      • 2011-02-18
      • 2011-07-25
      • 2021-10-27
      • 1970-01-01
      • 1970-01-01
      • 2022-07-28
      相关资源
      最近更新 更多