代码之家  ›  专栏  ›  技术社区  ›  pablo

600K记录的数据库还是平面文件?

  •  2
  • pablo  · 技术社区  · 15 年前

    我正在写一个C#应用程序,它需要在某个时间点向数据库中插入大约60万条记录。

    他们是非常简单的记录:只有3长。

    在SqlServer上完成大约需要50秒,而在MySql上则更慢,而在平面文件上插入相同的数据只需要几秒钟。

    是我做错了什么还是数据库太慢了?

    12 回复  |  直到 15 年前
        1
  •  6
  •   Jeffrey Hantin    15 年前

    • ExecuteNonQuery 不会将多个insert语句分组到批中,因此每个记录都会发生完整的进程间通信周转。分组发送insert语句。
    • 您拥有的数据已经是一个平面文件的形状,因此您可以在一次写入或几次使用缓冲的写入中全部触发。
    • 数据库操作倾向于使用需要n logn时间的树,而简单的数组形式的构造则需要线性时间。另一方面,如果要合并到已排序的平面文件中,则需要一段时间。
        2
  •  3
  •   Remus Rusanu    15 年前

    如果您所需要的只是插入数据而从不将其读回,那么您可以编写一个noop函数并假装将它们插入/dev/nul。真正的问题是 您计划如何使用上述数据

        3
  •  2
  •   duffymo    15 年前

    因此,一行的时间大约是8毫秒,而整个文件的时间大约是8毫秒。公平吗?

    1. 解析、验证、执行SQL
    2. 计算任何索引的值
    3. 管理回滚日志(如果这是单个事务)

    我假设您是在本地运行的,所以不需要考虑网络延迟。

    所以我猜数据库的速度会慢一些。不过,我没想到会慢60万倍。

        5
  •  1
  •   Chris Klepeis    15 年前

    你在大批量插入吗?如果你还没学会,我会用的。

    INSERT INTO dbo.NewTable(fields) 
    SELECT fields 
    FROM dbo.oldTable 
    WHERE ...
    

    在上面的示例中,您希望确保select语句中使用的表具有适当的索引。。。将聚集索引正确分配给最相关的字段。

    如果select语句很慢,请检查执行计划以可能找到瓶颈。

        6
  •  1
  •   jrista    15 年前

    我帮不了你多少忙。但是,SQLServer2005和更高版本提供了一些非常有趣的XML支持,可能会对您有所帮助。我建议您查看Updategrams,这是一种允许您提交一批要插入、更新或删除的数据的功能。这可能有助于提高SQLServer的性能,因为您只需要发出一条语句,而不需要发出600000条语句。我不确定它是否会像写入原始文件一样快,但它应该比发出单个语句快得多。

    http://msdn.microsoft.com/en-us/library/aa258671(SQL.80).aspx

        7
  •  1
  •   Dan F    15 年前

    ExecuteNonQuery 情况。 Opening Up Query Batching 是他说的介绍信吗 SqlCommandSet There Be Dragons: Rhino.Commons.SqlCommandSet .

    如果可以针对SQL2008进行优化,还可以尝试新的表值参数。 This sqlteam article 是一个很好的介绍给他们。

        8
  •  1
  •   Sam Saffron James Allen    12 年前

    正如Alex所说:使用SqlBulkCopy,在性能方面没有什么比它更好的了。

    http://github.com/SamSaffron/So-Slow/blob/1552b1293525bfe36f6c9b522e370de626ac6f05/Importer.cs

        9
  •  0
  •   Kostas Konstantinidis    15 年前

    您可能在数据库服务器上一遍又一遍地运行该命令,如果您构造一个包含多个插入的命令文本,然后运行该命令呢?ie公司

    string commandText = "insert into x ( y, z) values ( 1, 2 );\r\n"
    commandText += "insert into x ( y, z) values ( 2, 3 );"
    
    command.Text = commandText;
    command.ExecuteNonQuery();
    
        10
  •  0
  •   Gman Gman    15 年前

    如果您不需要很多并发用户,请尝试使用msjet,即“microsoftaccess”作为您的DBMS。MSJet的性能可以比SqlServer快10倍左右。顺便说一句,对于SqlServer来说,在50秒内插入600k条记录(12k/秒)非常快。

        11
  •  0
  •   Brent Ozar    15 年前

    我猜您正在进行事务性插入:插入如下所示:

    INSERT INTO dbo.MyTable (Field1, Field2, Field3)
    VALUES (50, 100, 150)
    

    这是可行的,但正如你所发现的,这是不可扩展的。为了快速地将大量数据推入SQLServer,有一些工具和技术可以实现。

    可能最简单的方法就是BCP。这里有几个关于它的链接:

    接下来,你也要摆桌子了。表上有约束和索引吗?您是否已经有其他记录在其中,并且您是否有其他人同时查询它?如果是这样,请考虑为没有索引或约束的数据加载构建一个空表。尽可能快地转储其中的所有数据,然后应用约束或索引,或者将数据移动到其最终目的地。

        12
  •  0
  •   devio    15 年前

    我的SQL Server 2005解决方案

    StringBuilder sb = new StringBuilder();
    bool bFirst = true;
    
    foreach(Record r in myData)
    {
        if (bFirst)
            sb.AppendLine("INSERT INTO tbl (f1, f2, f3)");
        else
            sb.AppendLine("UNION ALL");
        bFirst = false;
    
        sb.AppendLine("SELECT " + r.data1.ToString() + "," + 
            r.data2.ToString() + "," + r.data3.ToString());
    }
    
    SqlCommand cmd = new SqlCommand(sb.ToString(), conn);
    cmd.ExecuteNonQuery();