优化长时间运行的插入查询

时间:2015-07-16 07:52:34

标签: c# sql-server

我有以下代码,它工作正常。我的问题是插入花了三个多小时。

如何在sql表中优化插入查询?

foreach(var sheetName in GetExcelSheetNames(connectionString)) {
    using(OleDbConnection con1 = new OleDbConnection(connectionString)) {

        var dt = new DataTable();
        string query = string.Format("SELECT  * FROM [{0}]", sheetName);
        con1.Open();
        OleDbDataAdapter adapter = new OleDbDataAdapter(query, con1);
        adapter.Fill(dt);

        using(SqlConnection con = new SqlConnection(consString)) {
            con.Open();
            for (int i = 2; i < dt.Rows.Count; i++) {
                for (int j = 1; j < dt.Columns.Count; j += 3) {
                    try {
                        var s = dt.Rows[i][0].ToString();
                        var dt1 = DateTime.Parse(s, CultureInfo.GetCultureInfo("fr-FR"));
                        var s1 = dt.Rows[i][j].ToString();

                        var s2 = dt.Rows[i][j + 1].ToString();
                        var s3 = sheetName.Remove(sheetName.Length - 1);

                        {
                            SqlCommand command = new SqlCommand("INSERT INTO [Obj CA MPX] ([CA TTC],[VAL MRG TTC],[CA HT],[VAL MRG HT],[Rayon],[Date],[Code Site]) VALUES(@ca,@val,@catHT ,@valHT ,@rayon, @date ,@sheetName )", con);
                            command.Parameters.Add("@date", SqlDbType.Date).Value = dt1;
                            command.Parameters.AddWithValue("@ca", s1);
                            command.Parameters.AddWithValue("@val", s2);
                            command.Parameters.AddWithValue("@rayon", dt.Rows[0][j].ToString());
                            command.Parameters.AddWithValue("@sheetName", s3);
                            command.Parameters.Add("@catHT", DBNull.Value).Value = DBNull.Value;
                            command.Parameters.Add("@valHT", DBNull.Value).Value = DBNull.Value;
                            command.ExecuteNonQuery();
                        }
                    }
                }

4 个答案:

答案 0 :(得分:1)

也许您应该将其保存为文件并使用批量插入

https://msdn.microsoft.com/de-de/library/ms188365%28v=sql.120%29.aspx

答案 1 :(得分:0)

SQL Server可以选择使用Bulk Insert

Here是关于导入csv的好文章。

答案 2 :(得分:0)

您应首先阅读Eric Lippert撰写的这篇文章:Which is faster? 在尝试优化流程时请记住这一点。

插入花了3个小时,但是你插入了10个物品还是900.000.000.000个物品? 如果它是最后一个,那么3个小时就可以了。

你的数据库是什么? SQL Server 2005 Express? SQL Server 2014企业版? 建议可能有所不同。

如果没有更多详细信息,我们只能根据您的配置向您提供可能适用或不适用的建议 以下是我头脑中的一些内容:

  • 数据库方面的瓶颈是什么?检查执行计划,根据需要添加索引
  • 谨防AddWithValue,它可以阻止您在查询中使用索引
  • 如果要在非实时数据库上加载大量数据,可以使用较轻的recovery model来防止出现大量无用日志(使用批量加载将自动使用BULKED_LOGGED,或者您可以激活SIMPLE恢复模式(alter database [YourDB] set recovery SIMPLE,不要忘记重新启用FULL恢复模式)
  • 除了从Excel文件加载数据之外还有其他选择吗?您不能使用其他数据库或将Excel文件转换为CSV吗?
  • 性能监视器告诉您什么?也许你需要更好的硬件(更多内存,更快的磁盘,RAID),或者在一些不同的磁盘上移动一些使用频繁的文件(mdf,ldf)。
  • 您可以多次复制Excel文件并使用并行化,加载到最终表格分区的不同表格中。

此列表可以永久持续。

这是一篇关于优化数据加载的有趣文章:We Loaded 1TB in 30 Minutes with SSIS, and So Can You
本文主要关注SSIS,但有些建议并不仅适用于它。

答案 3 :(得分:0)

您可以使用字符串构建器将多个(例如100个)插入到字符串中。使用参数名称的索引。请注意,一个查询最多可以包含2100个参数。

StringBuilder batch = new StringBuilder();
for (int i = 0; i < pageSize; i++)
{
  batch.AppendFormat(
    @"INSERT INTO [Obj CA MPX] ([CA TTC],[VAL MRG TTC], ...) VALUES(@ca{0},@val{0}, ...)"
    i);
  batch.AppendLine();
  batch.AppendLine();
}

SqlCommand command = new SqlCommand(batch.ToString(), con)

// append parameters, using the index
for (int i = 0; i < pageSize; i++)
{
  command.Parameters.Add("@date" + i, SqlDbType.Date).Value = dt1[i];
  command.Parameters.AddWithValue("@ca" + i, s1[i]);
  // ...
}

command.ExecuteNonQuery();

当然这还没有完成,你必须将页面集成到你现有的循环中,这可能不会太简单。

或者,您不使用参数并将参数直接放入查询中。这样,您可以创建更大的批次(我会在一个批次中放置1000到10000个插入),并且它更容易实现。