C# MSSMS和Windows客户端之间的查询时间差异很大

C# MSSMS和Windows客户端之间的查询时间差异很大,c#,sql-server,performance,azure,tsql,C#,Sql Server,Performance,Azure,Tsql,我开发了一个WPF客户端,它使用Azure SQL数据库查询装运发票 客户一直抱怨装运列表的装载时间过长,我发现对于每个装运,应用程序都会查询Azure SQL数据库以获取装运发票,这需要时间 查询是在每个装运的foreach循环中进行的,没有其他方法可以完成,因为装运是通过在客户机中进行过滤从web服务加载的。 发票表没有要使用筛选器的列 为了测试这一点,我做了以下工作: 创建了一个TSQL脚本,该脚本在100个装运上运行动态sql以获取发票,并在SQLServerManagementStud

我开发了一个WPF客户端,它使用Azure SQL数据库查询装运发票

客户一直抱怨装运列表的装载时间过长,我发现对于每个装运,应用程序都会查询Azure SQL数据库以获取装运发票,这需要时间

查询是在每个装运的foreach循环中进行的,没有其他方法可以完成,因为装运是通过在客户机中进行过滤从web服务加载的。 发票表没有要使用筛选器的列

为了测试这一点,我做了以下工作:

  • 创建了一个TSQL脚本,该脚本在100个装运上运行动态sql以获取发票,并在SQLServerManagementStudio中执行。 对100个装运中的每个装运执行动态SQL。 我记录了动态sql执行之前和之后的时间 每个装运的动态sql ExecutionExecutionTime为0毫秒,这足够快了

  • 在C#中创建了一个控制台应用程序,可从Azure收集100批货件 将它们存储在列表中,然后运行查询以在列表上的foreachloop中获取发票。每次装运的执行时间在43到58毫秒之间变化,这太长了

  • 为了进行基准测试,我在我们网络中自己的一台SQL服务器上创建了Invoice表,从Azure SQLdatabase复制了数据,并运行了控制台应用程序。 每次装运的执行时间在0到15毫秒之间变化,这已经足够快了

    所以我的问题是,在MicrosoftSQLServerManagementStudio中以循环方式运行100个查询与在控制台应用程序中运行100个查询之间,如何会有如此巨大的差异?MSMS有神奇的连接吗

  • 样本代码:

    //Console application
    
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.Threading.Tasks;
        using System.Data.SqlClient;
        using System.Data;
    
        using System.IO;
    
        namespace ConsoleApp8
        {
            class Program
            {
                public struct res
                {
                    public string ShipmentId;
                    public DateTime St;
                    public DateTime Sl;
                    public double Exectimems;
    
                    public res(string shipmentid, DateTime st)
                    {
                        ShipmentId = shipmentid;
                        St = st;
                        Sl = new DateTime();
                        Exectimems = 0;
                    }
                }
    
    
                static void Main(string[] args)
                {
    
                    //string connstr = "Data Source=LocalNetWorkSQLServer;Initial Catalog=Dummy;User ID=sa;Password=somepassword;MultipleActiveResultSets=True";
                    string connstr = "Server = tcp:Server.database.windows.net;Database=Dummy;User ID =Username@Server;Password=somepassword;Trusted_Connection=False;Encrypt=True;MultipleActiveResultSets=True;";
                    List<string> Shipments = new List<string>();
                    List<res> results = new List<res>();
    
                    SqlConnectionStringBuilder scb = new SqlConnectionStringBuilder(connstr);
                    //Get all shipments to find invoices on and put them in a list.
                    string sql = "Select top 100 ShipmentId"
                    + " From("
                    + " Select distinct shipmentid"
                    + " From TKL_Invoices With(readuncommitted)"
                    + " Where OfficeId = 'swe') x";
    
    
                    using (SqlConnection cnn = new SqlConnection(connstr))
                    {
                        cnn.Open();
    
                        using (SqlCommand cmd = new SqlCommand(sql, cnn))
                        {
                            cmd.CommandType = System.Data.CommandType.Text;
    
                            SqlDataReader rd = cmd.ExecuteReader();
                            while (rd.Read())
                            {
                                Shipments.Add(rd["ShipmentId"].ToString());
                            }
    
                        }
                        cnn.Close();
                    }
    
    
                    //Get first invoice on each shipment
                    sql = "TKL_GetSavedInvoices";
                    using (SqlConnection cnn = new SqlConnection(connstr))
                    {
                        cnn.Open();
    
                        foreach (string Shipment in Shipments)
                        {
                            res r = new res(Shipment, DateTime.Now);
    
                            using (SqlCommand cmd = new SqlCommand(sql, cnn))
                            {
                                cmd.CommandType = System.Data.CommandType.StoredProcedure;
    
                                cmd.CommandType = System.Data.CommandType.StoredProcedure;
                                cmd.Parameters.AddWithValue("@ShipmentId", Shipment);
                                cmd.Parameters.AddWithValue("@OfficeId", "swe");
                                cmd.Parameters.AddWithValue("@Dbg", "1");
    
                                string invoice = cmd.ExecuteScalar().ToString();
    
                                r.Sl = DateTime.Now;
                                TimeSpan timeDiff = r.St - r.Sl;
                                r.Exectimems = timeDiff.TotalMilliseconds;
    
                                results.Add(r);
    
                                Console.WriteLine(Shipment, r.Exectimems.ToString());
                            }
                        }
                        cnn.Close();
                    }
    
    
                    //Log result to file
                    string prefix = "NetWorkSQLServer";
                    if (scb.DataSource.ToLower().Contains("tcp:"))
                        prefix = "Azure";
    
                    string filename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WPF_Client_" + prefix + "_QueryResult_" + scb.DataSource.Replace(':','_') + "." + scb.InitialCatalog + ".csv"); 
                    if (File.Exists(filename))
                        File.Delete(filename);
    
                    StringBuilder sb = new StringBuilder();
                    sb.Append("ShipmentId;TimeBeforeQyery;TimeAfterQyery;QueryTimeMilliseconds");
                   foreach (res r in results)
                    {
                        sb.Append(Environment.NewLine)
                            .Append(r.ShipmentId).Append(";")
                            .Append(r.St.ToLongTimeString()).Append(";")
                            .Append(r.Sl.ToLongTimeString()).Append(";")
                            .Append(r.Exectimems.ToString()).Append(";");
                    }
    
                    File.WriteAllText(filename, sb.ToString());
    
                    Console.WriteLine("Done");
                    Console.ReadKey();
                }
            }
        }
    
    这是浪费

    foreach (string Shipment in Shipments)
    {
         res r = new res(Shipment, DateTime.Now);
    
         using (SqlCommand cmd = new SqlCommand(sql, cnn))
         {
               cmd.CommandType = System.Data.CommandType.StoredProcedure;
               cmd.CommandType = System.Data.CommandType.StoredProcedure;
               cmd.Parameters.AddWithValue("@ShipmentId", Shipment);
               cmd.Parameters.AddWithValue("@OfficeId", "swe");
               cmd.Parameters.AddWithValue("@Dbg", "1");
    
    为什么在每个循环上都会有一个新的命令,而不是保留这个命令

    public static void SQLLoop()
    {
        List<string> shipments = new List<string>();
        string sql = "adsffo;hkjasd";
        using (SqlConnection cnn = new SqlConnection("asfd"))
        {
            cnn.Open();
            using (SqlCommand cmd = new SqlCommand(sql, cnn))
            {
                cmd.CommandType = System.Data.CommandType.StoredProcedure;
                List<res> results = new List<res>();
    
                cmd.CommandType = System.Data.CommandType.StoredProcedure;;
                cmd.Parameters.Add("@ShipmentId", SqlDbType.VarChar, 100);
                cmd.Parameters.AddWithValue("@OfficeId", "swe");
                cmd.Parameters.AddWithValue("@Dbg", "1");
    
                foreach (string shipment in shipments)
                {
                    res r = new res(shipment, DateTime.Now);
                    cmd.Parameters["@ShipmentId"].Value = shipment;
    
                    string invoice = cmd.ExecuteScalar().ToString();
    
                    r.Sl = DateTime.Now;
                    TimeSpan timeDiff = r.St - r.Sl;
                    r.Exectimems = timeDiff.TotalMilliseconds;
    
                    results.Add(r);
    
                    Console.WriteLine(shipment, r.Exectimems.ToString());
                }
            }
        }
    }
    
    publicstaticvoidsqlloop()
    {
    列表装运=新列表();
    字符串sql=“adsfo;hkjasd”;
    使用(SqlConnection cnn=newsqlconnection(“asfd”))
    {
    cnn.Open();
    使用(SqlCommand cmd=newsqlcommand(sql,cnn))
    {
    cmd.CommandType=System.Data.CommandType.StoredProcess;
    列表结果=新列表();
    cmd.CommandType=System.Data.CommandType.StoredProcess;;
    cmd.Parameters.Add(“@ShipmentId”,SqlDbType.VarChar,100);
    cmd.Parameters.AddWithValue(“@OfficeId”,“swe”);
    cmd.Parameters.AddWithValue(“@Dbg”,“1”);
    foreach(装运中的字符串装运)
    {
    res r=新res(发货,日期时间.现在);
    cmd.Parameters[“@ShipmentId”].Value=shipping;
    字符串invoice=cmd.ExecuteScalar().ToString();
    r、 Sl=日期时间。现在;
    TimeSpan timeDiff=r.St-r.Sl;
    r、 Exectimems=timeDiff.total毫秒;
    结果:添加(r);
    Console.WriteLine(shipping,r.Exectimems.ToString());
    }
    }
    }
    }
    
    For 1)您是在运行一个脚本,然后是另一个脚本,然后是另一个脚本(即100个独立的
    Execute
    s)?还是只单击一次执行?是的,执行100次动态查询以获取发票。问题是运行100次查询。为什么不能使用单个查询?我知道你说这是使用一个web服务,但我会创建一个新的web方法来获取所有数据,而不是调用它100次。使用readuncommitted时要小心。尤其是发票之类的东西。这不是一个神奇的快速按钮,它与一些非常严重的行李。例如随机获取重复和/或丢失的行。还有一大堆其他“有趣”的东西。尝试在“If exists”查询中添加选项(针对未知进行优化),现在已经测试过了,没有任何区别。你得到了一个要点,但这不能解释C#和MSSM之间的区别,因为我在TSQL中也使用了一个新命令。问题是不要审查我的代码!不,您不会在SQL循环中的任何位置创建命令。您可以创建一个新的选择。对不起,我想帮忙。SQL没有魔力,你的代码只是有缺陷。好吧,那么我误解了动态SQL?我试试你的建议。解决了:找到了另一个解决办法。由于我现在使用ShipmentId,所以我对列表进行排序,获取最小和最大ShipmentId(它们采用固定格式,并且始终为数字),并通过一次查询获取所有发票。我试了100次,而且速度非常快。谢谢大家的意见。谢谢你们给我一个非常糟糕的问题,我的回答是书面的。你没有表现出编程或解决问题的能力。
    public static void SQLLoop()
    {
        List<string> shipments = new List<string>();
        string sql = "adsffo;hkjasd";
        using (SqlConnection cnn = new SqlConnection("asfd"))
        {
            cnn.Open();
            using (SqlCommand cmd = new SqlCommand(sql, cnn))
            {
                cmd.CommandType = System.Data.CommandType.StoredProcedure;
                List<res> results = new List<res>();
    
                cmd.CommandType = System.Data.CommandType.StoredProcedure;;
                cmd.Parameters.Add("@ShipmentId", SqlDbType.VarChar, 100);
                cmd.Parameters.AddWithValue("@OfficeId", "swe");
                cmd.Parameters.AddWithValue("@Dbg", "1");
    
                foreach (string shipment in shipments)
                {
                    res r = new res(shipment, DateTime.Now);
                    cmd.Parameters["@ShipmentId"].Value = shipment;
    
                    string invoice = cmd.ExecuteScalar().ToString();
    
                    r.Sl = DateTime.Now;
                    TimeSpan timeDiff = r.St - r.Sl;
                    r.Exectimems = timeDiff.TotalMilliseconds;
    
                    results.Add(r);
    
                    Console.WriteLine(shipment, r.Exectimems.ToString());
                }
            }
        }
    }