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

MS SQL Query in C# - poor 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();
    }
}

在这种情况下,您似乎正在使用多个代码循环执行多个查询,您也在查询图表两次。在这种情况下,您希望使用 Chart 中的 LEFT JOIN 到您的其他 tables.

ON Chart.Code = Salsum.Code
ON Chart.Code = Journal.Code

例如。 您还必须查看 GROUP BY,因为您正在使用 SUM 聚合一些 table 列。 您可能还需要确保代码已在您查询的 table 上建立索引。只要经常像这样查询 Code 并且相对很少更新或插入到,那么索引这些 table 上的 Code 列可能是合适的。 左连接: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,按代码分组

索引代码列

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

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

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