C#中的MS SQL查询 - 性能不佳

时间:2016-09-30 15:12:24

标签: sql sql-server ado.net query-performance

我在C#Winforms中计算出色的客户余额。下面的代码有效,但速度很慢。有没有办法改善其表现?

public DataTable GetOutStandingCustomers()
{
    decimal Tot = 0;

    DataTable table = new DataTable();

    SqlConnection con = null;
    try
    {

        table.Columns.Add("Code", typeof(Int32));
        table.Columns.Add("Name", typeof(string));
        table.Columns.Add("City", typeof(string));
        table.Columns.Add("Tot", typeof(decimal));


        string constr = ConfigHelper.GetConnectionString();

        string query = "SELECT Code, Name,City FROM Chart WHERE LEFT(CODE,3)='401' AND Code > 401001 ";
        string query0 = "  SELECT(SELECT ISNULL( SUM(SalSum.Grand),'0' ) FROM SalSum WHERE SalSum.Code = @Code ) +( SELECT  ISNULL(SUM(Journals.Amount),'0' ) FROM Journals WHERE Journals.DrCode = @Code ) -( SELECT  ISNULL(SUM(RSalSum.Grand),'0' ) FROM RSalSum WHERE RSalSum.Code = @Code ) -( SELECT  ISNULL(SUM(Journals.Amount),'0' )  FROM Journals WHERE Journals.CrCode = @Code )+(SELECT  ISNULL(SUM(Chart.Debit),'0' ) FROM Chart WHERE Chart.Code = @Code) - (SELECT  ISNULL(SUM(Chart.Credit), '0') FROM Chart WHERE Chart.Code = @Code)";

        Person per = new Person();

        con = new SqlConnection(constr);

        SqlCommand com = new SqlCommand(query, con);
        SqlCommand com0 = new SqlCommand(query0, con);

                    con.Open();

        SqlDataReader r = com.ExecuteReader();

        if (r.HasRows)
        {
            while (r.Read())
            {

                per.Name = Convert.ToString(r["Name"]);
                per.City = Convert.ToString(r["City"]);
                per.Code = Convert.ToString(r["Code"]);


                com0.Parameters.Clear();
                com0.Parameters.Add("@Code", SqlDbType.Int).Value = per.Code;


                Tot = Convert.ToDecimal(com0.ExecuteScalar());


                if (Tot != 0)
                {
                    table.Rows.Add(per.Code, per.Name, per.City, Tot);
                }

            }
        }
        r.Close();
        con.Close();

        return table;
    }
    catch (Exception)
    {
        throw new Exception();
    }
}

2 个答案:

答案 0 :(得分:0)

在这种情况下,您似乎正在循环并使用多个代码执行多个查询,您还要两次查询图表。在这种情况下,您需要使用Chart中的LEFT JOIN到其他表格。

ON Chart.Code = Salsum.Code
ON Chart.Code = Journal.Code
例如,

。 您还必须查看GROUP BY,因为您使用SUM汇总了一些表格列。 您可能还需要确保在您查询的表中索引代码。只要经常像这样查询代码并且相对很少更新或插入代码,那么在这些表上索引代码列可能是合适的。 左连接:https://technet.microsoft.com/en-us/library/ms187518(v=sql.105).aspx 建立索引:https://technet.microsoft.com/en-us/library/jj835095(v=sql.110).aspx

抱歉,我在这里写了一本关于你的书,但优化通常会导致很长的答案(尤其是SQL)。

tldr; 使用LEFT JOIN,按代码分组

索引代码列

答案 1 :(得分:0)

性能问题是由于您从服务器检索所有数据并使用从七个表中求和的复杂计算表达式过滤客户端中的数据:

           if (Tot != 0)
            {
                table.Rows.Add(per.Code, per.Name, per.City, Tot);
            }

这表示网络上的开销加上您手动将结果逐行添加到数据表中。

提供的解决方案使用CROSS APPLY根据计算的表达式在服务器中进行过滤 并直接从DataReader自动创建数据表。

CROSS APPLY的好处是所有列对主sql查询都是可行的,因此可以在ToT列上进行过滤,过滤在服务器(而不是客户端)中完成。

 public void SelctChart()
 {                  
    string sql2 = @"
      select c.Code, c.Name,c.City ,oo.T 
      from chart c
      cross apply 
         ( select c.code,  
           (   
               (select ISNULL( SUM(SalSum.Grand),0 ) FROM SalSum WHERE SalSum.Code = c.code ) 
            +( select  ISNULL(SUM(j.Amount),0 ) FROM   [dbo].[Jornals] j WHERE j.DrCode = c.code)
            -( SELECT  ISNULL(SUM(RSalSum.Grand),'0' ) FROM RSalSum WHERE RSalSum.Code = c.Code ) 
            -( SELECT  ISNULL(SUM(j.Amount),0 )  FROM   [dbo].[Jornals] j WHERE j.CrCode = c.code )
            +(SELECT  ISNULL(SUM( c0.Debit),0 ) FROM [dbo].Chart c0  WHERE c0.Code = c.code) 
            - (SELECT  ISNULL(SUM(c1.Credit), 0) FROM [dbo].Chart c1  WHERE c1.Code = c.code)  
           )T   
         ) oo
     where 
       oo.T >0   
       and LEFT(c.CODE,3)='401' AND c.Code > 401001
    ";


        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            SqlCommand command = new SqlCommand(sql2, connection);
            //in case you pass @code as a a parameter
            //command.Parameters.Add("@code", SqlDbType.Int);
            //command.Parameters["@code"].Value = code;

            try
            {
                connection.Open();
                var reader = command.ExecuteReader();
                while (!reader.IsClosed)
                {
                    DataTable dt = new DataTable();
                    // Autoload datatable
                    dt.Load(reader);
                    Console.WriteLine(dt.Rows.Count);

                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

您可以修改方法并将代码作为参数传递