2013-06-03 3 views
3

dans mon code, l'utilisateur peut télécharger un document excel souhait contient sa liste de contacts téléphoniques.Me en tant que développeur devrait lire ce fichier excel le transformer en un dataTable et l'insérer dans le base de données . Le problème est que certains clients ont une quantité énorme de contacts comme dire 5000 contacts et plus et quand j'essaye d'insérer cette quantité de données dans la base de données il s'écrase et me donne une exception de délai d'attente. Quel serait le meilleur moyen d'éviter ce genre d'exception et est-ce que leur code peut réduire le temps de l'instruction d'insertion afin que l'utilisateur n'attende pas trop longtemps?Traiter une énorme quantité de données lors de l'insertion dans la base de données SQL

le code

public SqlConnection connection = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString); 
public void Insert(string InsertQuery) 
{ 
    SqlDataAdapter adp = new SqlDataAdapter(); 
    adp.InsertCommand = new SqlCommand(InsertQuery, connection); 
    if (connection.State == System.Data.ConnectionState.Closed) 
    { 
     connection.Open(); 
    } 
    adp.InsertCommand.ExecuteNonQuery(); 
    connection.Close(); 
} 

protected void submit_Click(object sender, EventArgs e) 
{ 
    string UploadFolder = "Savedfiles/"; 
    if (Upload.HasFile) { 
     string fileName = Upload.PostedFile.FileName; 
     string path=Server.MapPath(UploadFolder+fileName); 
     Upload.SaveAs(path); 
     Msg.Text = "successfully uploaded"; 
     DataTable ValuesDt = new DataTable(); 
     ValuesDt = ConvertExcelFileToDataTable(path); 
     Session["valuesdt"] = ValuesDt; 
     Excel_grd.DataSource = ValuesDt; 
     Excel_grd.DataBind(); 


    } 
} 

protected void SendToServer_Click(object sender, EventArgs e) 
{ 
    DataTable Values = Session["valuesdt"] as DataTable ; 
    if(Values.Rows.Count>0) 
    { 
     DataTable dv = Values.DefaultView.ToTable(true, "Mobile1", "Mobile2", "Tel", "Category"); 
     double Mobile1,Mobile2,Tel;string Category=""; 
     for (int i = 0; i < Values.Rows.Count; i++) 
     { 
      Mobile1 =Values.Rows[i]["Mobile1"].ToString()==""?0: double.Parse(Values.Rows[i]["Mobile1"].ToString()); 
      Mobile2 = Values.Rows[i]["Mobile2"].ToString() == "" ? 0 : double.Parse(Values.Rows[i]["Mobile2"].ToString()); 
      Tel = Values.Rows[i]["Tel"].ToString() == "" ? 0 : double.Parse(Values.Rows[i]["Tel"].ToString()); 

      Category = Values.Rows[i]["Category"].ToString(); 
      Insert("INSERT INTO client(Mobile1,Mobile2,Tel,Category) VALUES(" + Mobile1 + "," + Mobile2 + "," + Tel + ",'" + Category + "')"); 
      Msg.Text = "Submitied successfully to the server "; 
     } 



    } 

} 
+3

Vous pourriez faire quelques tests avec insert en vrac ou de la table des paramètres évalués. Sachez également que votre code est actuellement sujet à l'injection SQL et que sa gestion des exceptions est médiocre. –

+0

c'est juste un projet de test et ce n'est pas le projet de production – Sora

+0

Vous savez que 'SqlDataAdapter' dans votre méthode' Insert' ne fait * rien du tout *, non? Mais en effet: paramètres ... dans le code réel: certainement besoin de –

Répondre

4

vous pouvez essayer d'insérer SqlBulkCopy Datatable au tableau de base de données

Quelque chose comme ça,

using (SqlBulkCopy bulkCopy = new SqlBulkCopy(sqlConnection, SqlBulkCopyOptions.KeepIdentity)) 
{ 
    bulkCopy.DestinationTableName = DestTableName; 
    string[] DtColumnName = YourDataTableColumns; 
    foreach (string dbcol in DbColumnName)//To map Column of Datatable to that of DataBase tabele 
    { 
     foreach (string dtcol in DtColumnName) 
     { 
      if (dbcol.ToLower() == dtcol.ToLower()) 
      { 
       SqlBulkCopyColumnMapping mapID = new SqlBulkCopyColumnMapping(dtcol, dbcol); 
       bulkCopy.ColumnMappings.Add(mapID); 
       break; 
      } 
     } 
    } 
    bulkCopy.WriteToServer(YourDataTableName.CreateDataReader()); 
    bulkCopy.Close(); 
} 

Pour plus Lire http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx

1

Vous insérez 1 ligne à la fois, ce qui est très cher pour cette quantité de données

Dans ces cas, vous devez utiliser insert en vrac, de sorte que le voyage aller-retour à la DB sera une seule fois, si vous avez besoin de revenir - tout est la même transaction

0

Vous pouvez utiliser SqlBulkCopy qui est plus de travail, ou vous pouvez utiliser la fonction de mise à jour de lot du SqlAdpater. Au lieu de créer votre propre instruction d'insertion, puis de créer un sqladapter, puis de l'exécuter manuellement, créez un dataset, remplissez-le, créez un sqldataadpater, définissez le nombre d'insertions dans un lot, puis exécutez l'adaptateur une fois.

je pouvais répéter le code, mais cet article montre exactement comment le faire: http://msdn.microsoft.com/en-us/library/kbbwt18a%28v=vs.80%29.aspx

protected void SendToServer_Click(object sender, EventArgs e) 
{ 
    DataTable Values = Session["valuesdt"] as DataTable ; 
    if(Values.Rows.Count>0) 
    { 
     DataTable dv = Values.DefaultView.ToTable(true, "Mobile1", "Mobile2", "Tel", "Category"); 
     //Fix up default values 
     for (int i = 0; i < Values.Rows.Count; i++) 
     { 
      Values.Rows[i]["Mobile1"] =Values.Rows[i]["Mobile1"].ToString()==""?0: double.Parse(Values.Rows[i]["Mobile1"].ToString()); 
      Values.Rows[i]["Mobile2"] = Values.Rows[i]["Mobile2"].ToString() == "" ? 0 : double.Parse(Values.Rows[i]["Mobile2"].ToString()); 
      Values.Rows[i]["Tel"] = Values.Rows[i]["Tel"].ToString() == "" ? 0 : double.Parse(Values.Rows[i]["Tel"].ToString()); 

      Values.Rows[i]["Category"] = Values.Rows[i]["Category"].ToString(); 
     } 
     BatchUpdate(dv,1000); 


    } 

} 
public static void BatchUpdate(DataTable dataTable,Int32 batchSize) 
{ 
    // Assumes GetConnectionString() returns a valid connection string. 
    string connectionString = GetConnectionString(); 

    // Connect to the database. 
    using (SqlConnection connection = new SqlConnection(connectionString)) 
    { 

     // Create a SqlDataAdapter. 
     SqlDataAdapter adapter = new SqlDataAdapter(); 

     // Set the INSERT command and parameter. 
     adapter.InsertCommand = new SqlCommand(
      "INSERT INTO client(Mobile1,Mobile2,Tel,Category) VALUES(@Mobile1,@Mobile2,@Tel,@Category);", connection); 
     adapter.InsertCommand.Parameters.Add("@Mobile1", 
      SqlDbType.Float); 
     adapter.InsertCommand.Parameters.Add("@Mobile2", 
      SqlDbType.Float); 
     adapter.InsertCommand.Parameters.Add("@Tel", 
      SqlDbType.Float); 
     adapter.InsertCommand.Parameters.Add("@Category", 
      SqlDbType.NVarchar, 50); 
     adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.None; 

     // Set the batch size. 
     adapter.UpdateBatchSize = batchSize; 

     // Execute the update. 
     adapter.Update(dataTable); 
    } 
} 
+0

la taille du lot est la quantité de ligne à insérer à la fois? – Sora

+0

Oui. Vous pouvez également spécifier 0 pour lui permettre d'utiliser la taille maximale possible. Vous pouvez également connecter des événements à l'adaptateur pour vous permettre de surveiller sa progression. Dans ce cas, vous obtiendrez un événement pour tous les enregistrements 'batchsize' qu'il a mis à jour. Vous constaterez probablement que vos gains de performance les plus importants vont de 1 à 10, une amélioration significative des performances allant de 10 à 100, et une amélioration mineure allant de 100 à 1000, et négligeable allant plus haut que cela. Les performances dépendent de la taille des données et de la latence de votre client sur le serveur SQL. –

+1

Juste pour que vous sachiez, si vous pouvez faire fonctionner le SqlBulkCopy, il n'y a tout simplement pas de moyen plus rapide de le faire, mais il y a des pièges dont vous devez tenir compte. Cela peut être difficile, et cela peut aussi être difficile. Par exemple, il n'aime pas les nouveaux types DateTime SQL Server 2008. C'est pourquoi je préfère généralement les mises à jour par lots de SqlAdapter à moins que les performances les plus rapides soient requises à partir de SqlBulkCopy. –

Questions connexes