2016-09-06 1 views
0

私のC#デスクトップアプリケーションは、フォームItemsBrowserを持って取得します。私のアプリケーションはInventoryシステムに関するものです。 ItemsBrowserフォームは、ユーザーが新しい販売または新規購入を追加している間に明細の詳細を読み込みます。ここにはLoadAllItems()コード: -C#デスクトップアプリケーション:SQL Serverのアクセスが急に遅く

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; 
    } 

この機能はうまく動作していました。しかし突然、それは非常に遅くなった。ループ内のいずれかによって各ライン1をチェックすることにより、私は ItemCategory ItemCat = dbc.GetThisItemCategory(itm.ItemCategoryCode); のようなデータベースにアクセスする文は、データベースへのアクセスが非常に遅くなったときにことがわかりました。以前はかなりうまく走っていましたが。テーブルには合計955項目があります。 ALSO

私は、クライアントのマシン上でこのアプリケーションをインストールしているし、それは遅延なしで、クライアントのマシン上に存在し正常に動作している...

に気づいた非常に奇妙なこと...

getAllItemsというメソッド()機能

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()関数

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; 
} 

実際には、問題は特定の機能に関するものではありません。これは、GetThisItemCategory()またはGetPresentStock_By_ItemID()関数のいずれであっても、データベースアクセスに関するものです。

それはかなりFINE働いていた以前のバージョンをご注意ください。いつもこの方法で起動しています...

+0

'GetThisItemCategory'メソッドが呼び出されているときにSQLサーバーで実行されている実際のクエリを捕捉して、SQL Serverプロファイラを実行します。次に、サーバーでこのクエリを実行します。実行時間がほぼ同じ場合は、クエリのパフォーマンスを向上させる方法を見つける必要があります(おそらくインデックスなどを作成する)。それ以外の場合は、DBConnectorに問題があります。 –

+0

GetThisItemCategory関数とdbc.GetAllItems()関数のロジックは何ですか? –

+0

GetThisItemCategory()とGetAllItems()関数のコードを提供しました... –

答えて

1

注入されたSQL攻撃から保護し、RDBMSから最大限のプランを再利用するために、「名前付きパラメータ」の実行方法を学ぶ必要があります。ここで

は一例です:

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

あなたがこの記事では、動的SQLについていくつかのことを読むことができます。

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

(この記事対あなたは.cs C#の「インライン」SQL間のミニ重複があります...それはあなたが傾斜している場合は、さらに調査するためにいくつかのことをあげる)

.....

最後に、「インデックス調整」の基礎を学ぶ必要があります。あなたがここにそれにイントロを得ることができます

:推測として

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

、私は

ItemCategoriesにインデックスを作成します。ItemCategories.SupplierCode

上の別々のインデックスをItemCategoryCode

APPEND:最後に

、あなたは、このコードのバージョンを試すことができますか?

できるだけ早くDataReaderを削除して、接続プールの接続が不足しないようにします。

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

SQLクエリのパラメータを使用すると、パフォーマンスとデータの読み取り速度が向上しますか? –

+0

sqlmagの記事を読んでください。次に、パラメータをコード化し、sql-profilerでsqlを調べます。 sql-serverのコード(今送信された)がsqlmag記事のベストプラクティスについて話していることがわかります。 – granadaCoder

+0

ありがとう@granadaCoder –

関連する問題