C# MSSMS和Windows客户端之间的查询时间差异很大
我开发了一个WPF客户端,它使用Azure SQL数据库查询装运发票 客户一直抱怨装运列表的装载时间过长,我发现对于每个装运,应用程序都会查询Azure SQL数据库以获取装运发票,这需要时间 查询是在每个装运的foreach循环中进行的,没有其他方法可以完成,因为装运是通过在客户机中进行过滤从web服务加载的。 发票表没有要使用筛选器的列 为了测试这一点,我做了以下工作: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
//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());
}
}
}
}