2016-09-06 3 views
0

Mon application de bureau C# a un formulaire ItemsBrowser. Mon application concerne un système d'inventaire. Le formulaire ItemsBrowser charge les détails des articles pendant que l'utilisateur ajoute une nouvelle vente ou un nouvel achat. Voici LoadAllItems() code: -Application de bureau C#: l'accès à SQL Server devient soudainement lent

void LoadAllItems() 
    { 
     DBConnector dbc = new DBConnector(); 
     AccountsBasic.Classes.DBConnector dbca = new AccountsBasic.Classes.DBConnector(); 
     ArrayList lstItems = dbc.GetAllItems(); 
     var AddedItems = new List<DataGridViewRow>(); 

     Cursor.Current = Cursors.WaitCursor; 
     dgvItems.Rows.Clear(); 
     for (int i=0; i<=lstItems.Count-1; i++) 
     { 
      Item itm = (Item)lstItems[i]; 
      ItemCategory ItemCat = dbc.GetThisItemCategory(itm.ItemCategoryCode); 
      DataGridViewRow row = new DataGridViewRow(); 
      row.CreateCells(dgvItems);    
      row.Cells[0].Value = dbca.GetThisParty(dbc.GetThisItemCategory(itm.ItemCategoryCode).SupplierCode).PartyName; 
      row.Cells[1].Value = ItemCat.ItemCategoryName; 
      row.Cells[2].Value = itm.ItemID.ToString(); 
      row.Cells[3].Value = itm.ItemName; 
      row.Cells[4].Value = itm.RetailPrice.ToString(); 
      row.Cells[5].Value = dbc.GetPresentStock_By_ItemID(itm.ItemID).ToString(); 

      AddedItems.Add(row); 
      //dgvItems.Rows.Add(dbca.GetThisParty(dbc.GetThisItemCategory(itm.ItemCategoryCode).SupplierCode).PartyName, dbc.GetThisItemCategory(itm.ItemCategoryCode).ItemCategoryName, itm.ItemID.ToString(), itm.ItemName, itm.RetailPrice, dbc.GetPresentStock_By_ItemID(itm.ItemID).ToString()); 
     } 

     dgvItems.Rows.AddRange(AddedItems.ToArray()); 
     dgvItems.AutoResizeColumns(); 
     Cursor.Current = Cursors.Default; 
    } 

Cette fonction fonctionnait bien et en vitesse. Mais soudainement, ça a beaucoup ralenti. En vérifiant chaque ligne une par une dans la boucle, j'ai trouvé que lorsqu'une instruction accédant à la base de données comme ItemCategory ItemCat = dbc.GetThisItemCategory(itm.ItemCategoryCode); l'accès à la base de données devient très lent. Bien qu'il courait assez bien avant. Il y a un total de 955 objets dans le tableau.

aussi une chose très étrange, j'ai remarqué ...

J'ai installé cette application sur la machine du client et il fonctionne très bien là-bas sur la machine client sans délai ...

getAllItems() fonction

public ArrayList GetAllItems(string SupplierCode = "", string ItemCategory = "") 
{ 
    if (SupplierCode != "" && ItemCategory != "") 
     comm.CommandText = "SELECT Items.ItemID, Items.ItemName, Items.Description, Items.ItemCategoryCode, Items.OpeningStock, Items.RetailPrice FROM Items, ItemCategories WHERE Items.ItemCategoryCode = ItemCategories.ItemCategoryCode AND ItemCategories.SupplierCode = '" + SupplierCode + "' AND ItemCategories.ItemCategory = '" + ItemCategory + "' ORDER BY Items.ItemID"; 
    else if (SupplierCode != "" && ItemCategory == "") 
     comm.CommandText = "SELECT Items.ItemID, Items.ItemName, Items.Description, Items.ItemCategoryCode, Items.OpeningStock, Items.RetailPrice FROM Items, ItemCategories WHERE Items.ItemCategoryCode = ItemCategories.ItemCategoryCode AND ItemCategories.SupplierCode = '" + SupplierCode + "' ORDER BY ItemCategories.SupplierCode, ItemCategories.ItemCategory"; 
    else if (SupplierCode == "" && ItemCategory != "") 
     comm.CommandText = "SELECT Items.ItemID, Items.ItemName, Items.Description, Items.ItemCategoryCode, Items.OpeningStock, Items.RetailPrice FROM Items, ItemCategories WHERE Items.ItemCategoryCode = ItemCategories.ItemCategoryCode AND ItemCategories.ItemCategory = '" + ItemCategory + "' ORDER BY Items.ItemID"; 
    else 
     comm.CommandText = "SELECT * FROM Items Order By ItemID"; 

    ArrayList AllItems = new ArrayList(); 
    conn.Open(); 
    SqlDataReader dr; 
    dr = comm.ExecuteReader(); 
    while (dr.Read()) 
    { 
     Item it = new Item(); 
     it.ItemID = dr.GetInt32(0); 
     it.ItemName = dr.GetString(1); 
     it.Description = dr.IsDBNull(2) ? "" : dr.GetString(2); 
     it.ItemCategoryCode = dr.IsDBNull(3) ? -1 : dr.GetInt32(3); 
     it.OpeningStock = dr.IsDBNull(4) ? 0 : dr.GetInt32(4); 
     it.RetailPrice = dr.IsDBNull(5) ? 0 : dr.GetDouble(5); 

     AllItems.Add(it); 
    } 
    dr.Close(); 
    conn.Close(); 

    return AllItems; 
} 

GetThisItemCategory() fonction

public ItemCategory GetThisItemCategory(int ItemCategoryCode = -1, string SupplierCode = "", string ItemCategory = "") 
{ 
    if (ItemCategoryCode == -1 && SupplierCode != "" && ItemCategory != "") 
     comm.CommandText = "SELECT * FROM ItemCategories WHERE SupplierCode = '" + SupplierCode + "' AND ItemCategory = '" + ItemCategory + "' Order By SupplierCode, ItemCategory"; 
    else if (ItemCategoryCode == -1 && SupplierCode == "" && ItemCategory != "") 
     comm.CommandText = "SELECT * FROM ItemCategories WHERE ItemCategory = '" + ItemCategory + "' Order By ItemCategory"; 
    else// if (ItemCategoryCode != -1 && SupplierCode == "" && ItemCategory == "") 
     comm.CommandText = "SELECT * FROM ItemCategories WHERE ItemCategoryCode = '" + ItemCategoryCode + "' Order By SupplierCode, ItemCategory"; 

    SqlDataReader dr; 
    ItemCategory ic = new ItemCategory(); 
    ic.ItemCategoryCode = -1; 

    conn.Open(); 
    dr = comm.ExecuteReader(); 
    if (dr.Read()) 
    { 
     ic.ItemCategoryCode = dr.GetInt32(0); 
     ic.SupplierCode = dr.GetString(1); 
     ic.ItemCategoryName = dr.GetString(2); 
     ic.OrderableStockLimit = (dr.IsDBNull(3)) ? -1 : dr.GetInt32(3); 
    } 
    dr.Close(); 
    conn.Close(); 

    return ic; 
} 

En fait, le problème ne concerne pas la fonction spécifique. Il s'agit de n'importe quel accès à la base de données, que ce soit la fonction GetThisItemCategory() ou GetPresentStock_By_ItemID().

S'IL VOUS PLAÎT NOTEZ PLUS TÔT QU'IL TRAVAILLAIT JOLI FIN. Soudain, il a commencé à agir de cette façon ...

+0

Exécutez Sql Server profiler, capturez la requête réelle en cours d'exécution sur le serveur SQL lorsque la méthode GetThisItemCategory' est appelée. Ensuite, exécutez cette requête sur le serveur. Si le temps d'exécution est à peu près le même - vous devez trouver le moyen d'améliorer les performances de cette requête (en créant probablement des index, etc.), sinon c'est un problème avec votre 'DBConnector'. –

+0

Quelle est la logique de la fonction GetThisItemCategory et de la fonction dbc.GetAllItems()? –

+0

Avez fourni le code des fonctions GetThisItemCategory() et GetAllItems() ... –

Répondre

1

Vous devez apprendre à faire des "paramètres nommés", à protéger contre les attaques SQL injectées ET à obtenir une réutilisation maximale de votre SGBDR.

Voici un exemple:

using System; 
using System.Data; 
using System.Data.SqlClient; 

class ParamDemo 
{ 
    static void Main() 
    { 
     // conn and reader declared outside try 
     // block for visibility in finally block 
     SqlConnection conn = null; 
     SqlDataReader reader = null; 

     string inputCity = "London"; 
     try 
     { 
      // instantiate and open connection 
      conn = new 
       SqlConnection("Server=(local);DataBase=Northwind;Integrated Security=SSPI"); 
      conn.Open(); 

      // don't ever do this 
      // SqlCommand cmd = new SqlCommand(
      // "select * from Customers where city = '" + inputCity + "'"; 

      // 1. declare command object with parameter 
      SqlCommand cmd = new SqlCommand(
       "select * from Customers where city = @City", conn); 

      // 2. define parameters used in command object 
      SqlParameter param = new SqlParameter(); 
      param.ParameterName = "@City"; 
      param.Value   = inputCity; 

      // 3. add new parameter to command object 
      cmd.Parameters.Add(param); 

      // get data stream 
      reader = cmd.ExecuteReader(); 

      // write each record 
      while(reader.Read()) 
      { 
       Console.WriteLine("{0}, {1}", 
        reader["CompanyName"], 
        reader["ContactName"]); 
      } 
     } 
     finally 
     { 
      // close reader 
      if (reader != null) 
      { 
       reader.Close(); 
      } 

      // close connection 
      if (conn != null) 
      { 
       conn.Close(); 
      } 
     } 
    } 
} 

http://csharp-station.com/Tutorial/AdoDotNet/Lesson06

Vous pouvez lire quelques choses sur SQL dynamique dans cet article.

http://sqlmag.com/database-performance-tuning/don-t-fear-dynamic-sql

(Il y a un mini chevauchement entre vos .cs C# « en ligne » sql vs cet article ... ça va vous donner quelques petites choses à des recherches plus poussées si vous avez tendance)

.....

Enfin, vous devez apprendre les bases du "réglage d'index".

Vous pouvez obtenir une intro à ce ici:

https://sqlserverperformance.wordpress.com/2010/04/06/a-dmv-a-day-%E2%80%93-day-7/

Comme une supposition, je créerais un index sur

ItemCategories.ItemCategoryCode

et un index séparé sur

ItemCategories.SupplierCode

AJOUT:

Enfin, pouvez-vous essayer cette version du code?

Vous souhaitez vous débarrasser de DataReaders dès que possible, afin que votre pool de connexions ne soit pas à court de connexions.

public ItemCategory GetThisItemCategory(int ItemCategoryCode = -1, string SupplierCode = "", string ItemCategory = "") 
{ 

    using (SqlCommand cmd = new SqlCommand("MyConnectionString") 
    { 

     /* TO DO !!! , build your sql-string and parameter list here */ 

     using (IDataReader dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)) 
     { 

      if /*while*/ (dataReader.Read()) 
      { 
       ic.ItemCategoryCode = dr.GetInt32(0); 
       ic.SupplierCode = dr.GetString(1); 
       ic.ItemCategoryName = dr.GetString(2); 
       ic.OrderableStockLimit = (dr.IsDBNull(3)) ? -1 : dr.GetInt32(3); 
      } 

      if (dataReader != null) 
      { 
       try 
       { 
        dataReader.Close(); 
       } 
       catch { } 
      }   

     } 

     cmd.Close(); 

    } 

    return ic; 

} 
+0

L'utilisation de paramètres dans la requête SQL améliore-t-elle les performances et la vitesse de lecture des données? –

+0

Lisez l'article sqlmag. Ensuite, codez les paramètres et regardez le sql dans sql-profiler. Vous devriez voir que le code (maintenant envoyé) à sql-server parle des meilleures pratiques de l'article sqlmag. – granadaCoder

+0

Merci @granadaCoder –