简体   繁体   English

有助于减少与数据库的连接数

[英]help with reducing the number of connections to the database

I have a list of strings that are just invoice numbers. 我有一个字符串列表,它们只是发票编号。 I am enumerating through this list to get the details of each invoice from the database. 我将通过此列表进行枚举,以从数据库中获取每张发票的详细信息。 This list can easily be 700 to 1000 in size. 该列表的大小很容易为700到1000。 the way I am doing it now results in 700-1000 connections to the database. 我现在这样做的方式导致700-1000连接到数据库。 this is taking too long to complete is there a better way to do this that I just don't know about? 这需要太长时间才能完成是否有更好的方法来做到这一点,我只是不知道? Any pointers would be great. 任何指针都会很棒。

here is an example of my enumeration 这是我的枚举的一个例子

foreach(string i in invoiceList)
{
  Invoice inv = invoiceData.GetInvoice(i);
  //do something with the invoice
}

then here is an example of my data access method using ado.net 那么这是我使用ado.net的数据访问方法的一个例子

public Invoice GetInvoice(string invoice)
{
      SqlConnection con = new SqlConnection(//connection string);
      SqlCommand cmd = new SqlCommand("dbo.getInvoices", con);
      cmd.CommandType = CommandType.StoredProcedure;
      cmd.Parameters.Add("invoice", SqlDbType.VarChar).Value = invoice;
      SqlDataReader dr;
      Invoice inv = new Invoice();
      try{
            con.Open();
            dr = cmd.ExecuteReader
            while(dr.read())
            {
                 //assign values from the database fields
            }


      }
      catch{}
      finally{con.close();}

}

so basically the getInvoice method gets called 1000 times opening a new connection every time. 所以基本上getInvoice方法每次都会调用1000次打开一个新连接。 What is a better(faster) way to do this. 什么是更好(更快)的方法来做到这一点。 Thank you! 谢谢!

You can put your connection opening and closing code outside of your loop. 您可以将连接打开和关闭代码放在循环之外。 That would make you only have one connection to the database. 这将使您只有一个连接到数据库。 But that one connection would be open for a while. 但是这一个连接将暂时开放。 That's the trade-off. 这是权衡。 One connection open for a long time or lots of connections opening and closing. 一个连接打开很长时间或许多连接打开和关闭。

I am also noticing that you are not closing your connection in the try code. 我也注意到你没有在try代码中关闭你的连接。 Maybe try this. 也许试试这个。

public Invoice GetInvoice(string invoice)
{
      SqlConnection con = new SqlConnection(//connection string);
      SqlCommand cmd = new SqlCommand("dbo.getInvoices", con);
      cmd.CommandType = CommandType.StoredProcedure;
      cmd.Parameters.Add("invoice", SqlDbType.VarChar).Value = invoice;
      SqlDataReader dr;
      Invoice inv = new Invoice();
      try{
            con.Open();
            dr = cmd.ExecuteReader
            while(dr.read())
            {
                 //assign values from the database fields
            }
      }
      catch{}
      finally
      {
        con.Close();
      }
}

I'm missing the conn.Close() inside your try-block. 我在你的try-block中缺少conn.Close()

If it is really missing, that could be your problem: You keep making new connections all the time. 如果它确实缺失,那可能是你的问题:你一直在建立新的连接。 So, close it , in a try/finally block. 所以,在try / finally块中关闭它

But if this was a typo in the posted code, then I don't think your problem is related to the Connection(s), ADO.NET uses ConnectionPooling so you are keeping the 'real' connection open, even when you say conn.Close(). 但如果这是发布代码中的拼写错误,那么我认为您的问题与Connection无关,ADO.NET使用ConnectionPooling,因此您可以保持“真正的”连接打开,即使您说conn也是如此。关()。

The other issue would be doing a Query for every invoice. 另一个问题是对每张发票进行查询。 That is expensive too. 那也很贵。 But since you seem to use a SP it's not so easy to overcome. 但是既然你似乎使用了SP,那就不容易克服了。 What would be useful here is a SELECT statement that ends with WHERE Id IN (a, b, c, d) . 这里有用的是一个以WHERE Id IN (a, b, c, d)结尾的SELECT语句。 This would allow you to batch invoices (get 5 or 20 with 1 query. 这将允许您批量发票(通过1个查询获得5或20)。

只需将所有发票编号放在IN语句中,然后在单个连接中运行此select语句即可。

Something like this might be an improvement. 这样的事情可能会有所改善。

public List<Invoice> GetInvoices(List<string> invoiceList) {
  List<Invoice> invoices = new List<Invoice>();

  Invoice inv;
  SqlDataReader dr;

  using (SqlConnection con = new SqlConnection(//connection string)) {
    using(SqlCommand cmd = new SqlCommand("dbo.getInvoices", con)) {
      cmd.CommandType = CommandType.StoredProcedure;
      SqlParameter param = cmd.Parameters.Add("invoice", SqlDbType.VarChar);

      foreach(string i in invoiceList) {
        inv = new Invoice();
        param.Value = i;
        using (dr = cmd.ExecuteReader()) {
          while(dr.read())
          {
            // assign values from the database fields
            inv.Property = dr.GetString(0);

            // Add invoice to the result list
            invoices.Add(inv);
          }
        }
      }
    }
  }

  return invoices;
}

Then you can use this method like so... 然后就可以像这样使用这种方法......

var invoiceList = new List<string> { "123", "456", "789" };
var invoices = GetInvoices(invoiceList);
foreach(var i in invoices) {
  Console.WriteLine(i.SomeInvoiceProperty);
}

I believe you may want to consider a different approach if you consistently are processing 700 to 1000 or more invoice numbers at one time why not send all the invoice numbers down in a single query instead of many individual query's. 我相信如果您一直处理700到1000个或更多发票号码,为什么不在一个查询中发送所有发票号码而不是多个单独的查询,您可能想要考虑不同的方法。 As an example you could use an sql in list to do this as in below. 作为示例,您可以使用列表中的sql来执行此操作,如下所示。

select
 *
from
 ivoice_table
where
 invoice_table.invoice_number in (123,124,125,126,127,128 etc....)

Enjoy! 请享用!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM