c# - MSSMS 和 Windows 客户端的查询时间大不同
问题描述
我开发了一个 WPF 客户端,它使用 Azure SQL 数据库来查询发货发票。
客户一直在抱怨货件清单的加载时间过长,我发现对于每个货件,应用程序都会查询 Azure SQL 数据库以获取货件发票,这需要时间。
查询是在每个货物的 foreach 循环中进行的,并且没有其他方法可以做到这一点,因为货物是通过在客户端中过滤从 Web 服务加载的。发票表没有要使用过滤器的列。
因此,为了测试这一点,我做了以下操作:
创建了一个 TSQL 脚本,该脚本在 100 批货物上运行动态 sql 以获取发票并在 SQL Server 管理工作室中执行它。对 100 个装运中的每一个都执行动态 SQL。我记录了动态sql执行之前和动态sql执行之后的时间,每次发货的执行时间都是0毫秒,这已经足够快了。
在 C# 中创建了一个控制台应用程序,该应用程序从 Azure 收集 100 批货物,将它们存储在一个列表中,并运行查询以在列表上的 foreachloop 中获取发票。每批货物的执行时间在 43 到 58 毫秒之间变化,这太长了。
为了进行基准测试,我在网络中我们自己的一台 SQL 服务器上创建了 Invoice 表,从 Azure SQLdatabase 复制数据并运行控制台应用程序。每批货物的执行时间在 0 到 15 毫秒之间变化,这已经足够快了。
所以我的问题是,在 Microsoft SQLServer 管理工作室与控制台应用程序中循环运行 100 个查询之间怎么会有如此巨大的差异?MSSMS 有神奇的联系吗?
示例代码:
//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();
}
}
}
SQL数据库表:
/****** Object: Index [ix_TKL_Invoices001] Script Date: 2018-06-21 15:12:43 ******/
DROP INDEX [ix_TKL_Invoices001] ON [dbo].[Tkl_Invoices]
GO
/****** Object: Table [dbo].[Tkl_Invoices] Script Date: 2018-06-21 15:12:43 ******/
DROP TABLE [dbo].[Tkl_Invoices]
GO
/****** Object: Table [dbo].[Tkl_Invoices] Script Date: 2018-06-21 15:12:43 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Tkl_Invoices](
[ShipmentId] [varchar](50) NOT NULL,
[OfficeId] [varchar](50) NULL,
[InvoiceNo] [varchar](50) NOT NULL,
CONSTRAINT [PK_Tkl_Invoices] PRIMARY KEY CLUSTERED
(
[ShipmentId] ASC,
[InvoiceNo] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
/****** Object: Index [ix_TKL_Invoices001] Script Date: 2018-06-21 15:12:43 ******/
CREATE NONCLUSTERED INDEX [ix_TKL_Invoices001] ON [dbo].[Tkl_Invoices]
(
[OfficeId] ASC,
[ShipmentId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
--Data for the table
Insert into Tkl_Invoices(ShipmentId, OfficeId, InvoiceNo)
Select '1511546743', 'SWE', '250279'
Union Select '1512550199', 'SWE', '1111111'
Union Select '1512554318', 'SWE', '250249'
Union Select '1601561108', 'SWE', '250279'
Union Select '1602561957', 'SWE', '249700'
Union Select '1602562876', 'SWE', '250582'
Union Select '1602566412', 'SWE', '250577'
Union Select '1602567219', 'SWE', '249699'
Union Select '1602567387', 'SWE', '250577'
Union Select '1603568831', 'SWE', '250577'
Union Select '1603569044', 'SWE', '250326'
Union Select '1603569143', 'SWE', '249846'
Union Select '1603569720', 'SWE', '249994'
Union Select '1603570257', 'SWE', '250279'
Union Select '1603570259', 'SWE', '250582'
Union Select '1603570940', 'SWE', '1234'
Union Select '1603572374', 'SWE', '250118'
Union Select '1603572376', 'SWE', '250200'
Union Select '1603572378', 'SWE', '250034'
Union Select '1603572450', 'SWE', '249923'
Union Select '1603572450', 'SWE', '250262'
Union Select '1603572601', 'SWE', '249927'
Union Select '1603572603', 'SWE', '250577'
Union Select '1603573496', 'SWE', '249701'
Union Select '1603573826', 'SWE', '249712'
Union Select '1603574012', 'SWE', '250577'
Union Select '1603574022', 'SWE', '250055'
Union Select '1603574184', 'SWE', '249888'
Union Select '1603574193', 'SWE', '249702'
Union Select '1603574195', 'SWE', '250239'
Union Select '1603574417', 'SWE', '249921'
Union Select '1603574610', 'SWE', '1000000'
Union Select '1603574652', 'SWE', '249704'
Union Select '1603574865', 'SWE', '249706'
Union Select '1603574874', 'SWE', '250109'
Union Select '1603575030', 'SWE', '250175'
Union Select '1603575032', 'SWE', '250172'
Union Select '1603575127', 'SWE', '249732'
Union Select '1603575147', 'SWE', '250155'
Union Select '1603575181', 'SWE', '250108'
Union Select '1603575531', 'SWE', '250034'
Union Select '1603575538', 'SWE', '249994'
Union Select '1603575540', 'SWE', '250168'
Union Select '1603575558', 'SWE', '250084'
Union Select '1603575562', 'SWE', '250234'
Union Select '1603575566', 'SWE', '250057'
Union Select '1603575586', 'SWE', '250034'
Union Select '1603575592', 'SWE', '250193'
Union Select '1603575594', 'SWE', '250185'
Union Select '1603575598', 'SWE', '250034'
Union Select '1603575627', 'SWE', '250080'
Union Select '1603575633', 'SWE', '250163'
Union Select '1603575635', 'SWE', '249820'
Union Select '1603575637', 'SWE', '250108'
Union Select '1603575641', 'SWE', '250034'
Union Select '1603575644', 'SWE', '250102'
Union Select '1603575646', 'SWE', '250084'
Union Select '1603575653', 'SWE', '250117'
Union Select '1603575655', 'SWE', '250117'
Union Select '1603575868', 'SWE', '250084'
Union Select '1603575872', 'SWE', '250171'
Union Select '1603575874', 'SWE', '250036'
Union Select '1603575876', 'SWE', '250036'
Union Select '1603575879', 'SWE', '250036'
Union Select '1603575881', 'SWE', '250036'
Union Select '1603575887', 'SWE', '250036'
Union Select '1603575894', 'SWE', '250081'
Union Select '1603575896', 'SWE', '250065'
Union Select '1603575905', 'SWE', '250160'
Union Select '1603575909', 'SWE', '250083'
Union Select '1603575914', 'SWE', '250186'
Union Select '1603575917', 'SWE', '250105'
Union Select '1603575919', 'SWE', '250094'
Union Select '1603575921', 'SWE', '250183'
Union Select '1603575966', 'SWE', '250104'
Union Select '1603575976', 'SWE', '250124'
Union Select '1603575984', 'SWE', '250199'
Union Select '1603575992', 'SWE', '250501'
Union Select '1603575998', 'SWE', '250170'
Union Select '1603576000', 'SWE', '250034'
Union Select '1603576183', 'SWE', '250095'
Union Select '1603576188', 'SWE', '250114'
Union Select '1603576192', 'SWE', '250159'
Union Select '1603576209', 'SWE', '250129'
Union Select '1603576268', 'SWE', '250176'
Union Select '1603576286', 'SWE', '250130'
Union Select '1603576294', 'SWE', '249715'
Union Select '1603576296', 'SWE', '249716'
Union Select '1604576489', 'SWE', '250135'
Union Select '1604576823', 'SWE', '250036'
Union Select '1604576884', 'SWE', '250039'
Union Select '1604576909', 'SWE', '250145'
Union Select '1604576913', 'SWE', '249922'
Union Select '1604576944', 'SWE', '249682'
Union Select '1604577069', 'SWE', '249717'
Union Select '1604577112', 'SWE', '250082'
Union Select '1604577121', 'SWE', '250234'
Union Select '1604577133', 'SWE', '250234'
Union Select '1604577137', 'SWE', '250234'
Union Select '1604577139', 'SWE', '250234'
--SQL Stored procedure to get invoices(@Dbg is to get one invoice only)
/****** Object: StoredProcedure [dbo].[TKL_GetSavedInvoices] Script Date: 2018-06-21 15:23:51 ******/
DROP PROCEDURE [dbo].[TKL_GetSavedInvoices]
GO
/****** Object: StoredProcedure [dbo].[TKL_GetSavedInvoices] Script Date: 2018-06-21 15:23:51 ******/
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE procedure [dbo].[TKL_GetSavedInvoices]
@ShipmentId nvarchar(50)
,@OfficeId nvarchar(255) = null
,@Dbg smallint = 0
as
begin
declare @InvoiceNo nvarchar(50)
if Exists(Select 1 From TKL_Invoices with(readuncommitted)
where ShipmentId = @ShipmentId
and OfficeId = isnull(@OfficeId, OfficeId)
)
begin
If(@dbg = 0)
begin
select
InvoiceNo
from TKL_Invoices with(readuncommitted)
where ShipmentId = @ShipmentId
and OfficeId = isnull(@OfficeId, OfficeId)
order by Head desc
OPTION ( OPTIMIZE FOR UNKNOWN )
End Else
begin
select
@InvoiceNo = InvoiceNo
from TKL_Invoices with(readuncommitted)
where ShipmentId = @ShipmentId
and OfficeId = isnull(@OfficeId, OfficeId)
order by Head desc
OPTION ( OPTIMIZE FOR UNKNOWN )
Select @InvoiceNo as InvoiceNo
End
End Else
begin
Select 'NA' as InvoiceNo
End
end
GO
解决方案
这是浪费!
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());
}
}
}
}
推荐阅读
- html - Safari 垂直未对齐输入字段的值,并且不允许我使用填充
- c++ - 无法在 std::function<> 中传递 std::unique_ptr
- webpack - Prestashop - Webpack:_dev 文件夹已被删除我如何检索和更改 css 和 js 文件?
- excel - 使用自定义功能区创建 Excel 工作簿
- javascript - 是的布尔值模式(0或1)
- javascript - 使用 XMLHttpRequest POST 直接下载文件
- python - 百分比堆积条 - 在 Python Pandas 中实现百分比时出现语法错误?
- javascript - 如何计算对象javascript中的值
- angular - 角度测试,无法绑定到“ngIf”,因为它不是“div --- 导入的公共模块”的已知属性
- jquery - jCarouselLite 中主图像的导航按钮 - v1.1