2016-09-06 130 views
0

我的C#桌面应用程序的格式为ItemsBrowser。我的应用程序是关于库存系统。在用户添加新的销售或新购买时,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; 
    } 

此功能工作正常,速度。但突然它变得非常缓慢。通过检查循环中的每一行,我发现当访问数据库的语句像 ItemCategory ItemCat = dbc.GetThisItemCategory(itm.ItemCategoryCode); 时,数据库访问变得非常缓慢。虽然之前它运行得很好。表中共有955项。

也是一个很奇怪的事情,我注意到...

我已经安装了客户端的计算机上这个应用程序,它是客户端的机器在那里工作的罚款,没有延迟...

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()函数。

请注意以前它工作得很好。突然开始采用这种方式...

+0

运行Sql Server分析器,捕获在调用GetThisItemCategory方法时在SQL服务器上执行的实际查询。然后在服务器上运行此查询。如果执行时间大致相同 - 您需要找到提高查询性能的方式(可能会创建一些索引等),否则这是您的'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 VS这篇文章...它会给你一些事情,如果你倾向于进一步研究)

.....

最后,您需要了解“索引优化”的基础知识。

你可以得到一个介绍到这里:

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

作为一个猜测,我对

ItemCategories创建索引。ItemCategoryCode

一个单独的指数ItemCategories.SupplierCode

附加:

最后,你可以试试这个版本的代码?

您希望尽快摆脱DataReaders,因此您的连接池不会耗尽连接。

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

Thanks @granadaCoder –