C# ADO.NET SQL Server性能瓶颈
我有一个sql连接,我必须每秒访问数据库500到10000次。大约每秒250次之后,事情开始变慢,然后应用程序远远落后于它崩溃 我在考虑把数据库放进字典里。我需要最快的表现,我可以得到。目前ado.net大约需要1到2毫秒,但是发生了一些导致瓶颈的事情 对于每秒10k的查询,下面的语法是否有任何错误?字典有用吗?我们谈论的是1200万条记录,我需要能够在1到5毫秒内搜索它。数据库中还有另一个集合,有5000万条记录,所以我不知道如何存储它。任何建议都很好 SQL db有128 gb内存和80个处理器,应用程序位于SQL server 2012上的同一台服务器上C# ADO.NET SQL Server性能瓶颈,c#,sql,sql-server,ado,C#,Sql,Sql Server,Ado,我有一个sql连接,我必须每秒访问数据库500到10000次。大约每秒250次之后,事情开始变慢,然后应用程序远远落后于它崩溃 我在考虑把数据库放进字典里。我需要最快的表现,我可以得到。目前ado.net大约需要1到2毫秒,但是发生了一些导致瓶颈的事情 对于每秒10k的查询,下面的语法是否有任何错误?字典有用吗?我们谈论的是1200万条记录,我需要能够在1到5毫秒内搜索它。数据库中还有另一个集合,有5000万条记录,所以我不知道如何存储它。任何建议都很好 SQL db有128 gb内存和80个处
using (SqlConnection sqlconn = new SqlConnection(sqlConnection.SqlConnectionString()))
{
using (SqlCommand sqlcmd = new SqlCommand("", sqlconn))
{
sqlcmd.CommandType = System.Data.CommandType.StoredProcedure;
sqlcmd.Parameters.Clear();
sqlcmd.CommandTimeout = 1;
sqlconn.Open();
using (SqlDataReader sqlDR = sqlcmd.ExecuteReader(CommandBehavior.CloseConnection))
public static string SqlConnectionString()
{
return string.Format("Data Source={0},{1};Initial Catalog={2};User ID={3};Password={4};Application Name={5};Asynchronous Processing=true;MultipleActiveResultSets=true;Max Pool Size=524;Pooling=true;",
DataIP, port, Database, username, password, IntanceID);
}
datareader下面的代码是
r.CustomerInfo = new CustomerVariable();
r.GatewayRoute = new List<RoutingGateway>();
while (sqlDR.Read() == true)
{
if (sqlDR["RateTableID"] != null)
r.CustomerInfo.RateTable = sqlDR["RateTableID"].ToString();
if (sqlDR["EndUserCost"] != null)
r.CustomerInfo.IngressCost = sqlDR["EndUserCost"].ToString();
if (sqlDR["Jurisdiction"] != null)
r.CustomerInfo.Jurisdiction = sqlDR["Jurisdiction"].ToString();
if (sqlDR["MinTime"] != null)
r.CustomerInfo.MinTime = sqlDR["MinTime"].ToString();
if (sqlDR["interval"] != null)
r.CustomerInfo.interval = sqlDR["interval"].ToString();
if (sqlDR["code"] != null)
r.CustomerInfo.code = sqlDR["code"].ToString();
if (sqlDR["BillBy"] != null)
r.CustomerInfo.BillBy = sqlDR["BillBy"].ToString();
if (sqlDR["RoundBill"] != null)
r.CustomerInfo.RoundBill = sqlDR["RoundBill"].ToString();
}
sqlDR.NextResult();
r.CustomerInfo=新的CustomerVariable();
r、 网关路由=新列表();
while(sqlDR.Read()==true)
{
如果(sqlDR[“RateTableID”]!=null)
r、 CustomerInfo.RateTable=sqlDR[“RateTableID”].ToString();
如果(sqlDR[“EndUserCost”]!=null)
r、 CustomerInfo.ingrescost=sqlDR[“EndUserCost”].ToString();
if(sqlDR[“辖区”]!=null)
r、 CustomerInfo.directory=sqlDR[“辖区”].ToString();
if(sqlDR[“MinTime”]!=null)
r、 CustomerInfo.MinTime=sqlDR[“MinTime”].ToString();
if(sqlDR[“interval”]!=null)
r、 CustomerInfo.interval=sqlDR[“interval”].ToString();
if(sqlDR[“code”]!=null)
r、 CustomerInfo.code=sqlDR[“code”].ToString();
如果(sqlDR[“BillBy”]!=null)
r、 CustomerInfo.BillBy=sqlDR[“BillBy”].ToString();
if(sqlDR[“整单”]!=null)
r、 CustomerInfo.RoundBill=sqlDR[“RoundBill”].ToString();
}
sqlDR.NextResult();
如果您已经测量到ADO命令只需要几毫秒,那么造成延迟的另一个可能原因是用于构建connectionstring的string.Format
我将尝试删除为每个
using(SqlConnection cn = new SqlConnection(sqlConnection.SqlConnectionString()))
相反,假设SqlConnectionString位于单独的类中,您可以编写
private static string conString = string.Empty;
public static string SqlConnectionString()
{
if(conString == "")
conString = string.Format("............");
return conString;
}
当然,基准测试可以排除这一点,但我非常确信,像这样的字符串操作代价高昂
在下面看到您的评论另一件非常重要的事情是添加正确的参数声明。不要使用AddWithValue(方便但有棘手的副作用),而是用正确的大小声明参数
using (SqlCommand sqlcmd = new SqlCommand("", sqlconn))
{
sqlcmd.CommandType = System.Data.CommandType.StoredProcedure;
sqlcmd.CommandText = mySql.GetLCR();
SqlParameter p1 = new SqlParameter("@GatewayID", SqlDbType.NVarChar, 20).Value = GatewayID;
SqlParameter p2 = new SqlParameter("@DialNumber", SqlDbType.NVarChar, 20).Value = dialnumber;
sqlCmd.Parameters.AddRange(new SqlParameter[] {p1, p2});
sqlcmd.CommandTimeout = 1;
sqlconn.Open();
.....
}
当需要压缩每毫秒的性能时,不建议使用AddWithValue。解释为什么传递带有AddWithValue的字符串会破坏Sql Server优化器所做的工作。(简而言之,优化器为您的命令计算并存储一个查询计划,如果它收到另一个相同的命令,它将重用计算的查询计划。但是,如果您传递一个带有addwithvalue的字符串,则每次都会根据实际传递的字符串长度计算参数的大小。优化器无法重用查询计划和recalc创建并存储一个新命令)如果您已经测量到ADO命令只需要几毫秒,那么另一个可能的延迟原因是用于构建connectionstring的string.Format 我将尝试删除为每个
using(SqlConnection cn = new SqlConnection(sqlConnection.SqlConnectionString()))
相反,假设SqlConnectionString位于单独的类中,您可以编写
private static string conString = string.Empty;
public static string SqlConnectionString()
{
if(conString == "")
conString = string.Format("............");
return conString;
}
当然,基准测试可以排除这一点,但我非常确信,像这样的字符串操作代价高昂
在下面看到您的评论另一件非常重要的事情是添加正确的参数声明。不要使用AddWithValue(方便但有棘手的副作用),而是用正确的大小声明参数
using (SqlCommand sqlcmd = new SqlCommand("", sqlconn))
{
sqlcmd.CommandType = System.Data.CommandType.StoredProcedure;
sqlcmd.CommandText = mySql.GetLCR();
SqlParameter p1 = new SqlParameter("@GatewayID", SqlDbType.NVarChar, 20).Value = GatewayID;
SqlParameter p2 = new SqlParameter("@DialNumber", SqlDbType.NVarChar, 20).Value = dialnumber;
sqlCmd.Parameters.AddRange(new SqlParameter[] {p1, p2});
sqlcmd.CommandTimeout = 1;
sqlconn.Open();
.....
}
当需要压缩每毫秒的性能时,不建议使用AddWithValue。解释为什么传递带有AddWithValue的字符串会破坏Sql Server优化器所做的工作。(简而言之,优化器为您的命令计算并存储一个查询计划,如果它收到另一个相同的命令,它将重用计算的查询计划。但是,如果您传递一个带有addwithvalue的字符串,则每次都会根据实际传递的字符串长度计算参数的大小。优化器无法重用查询计划和recalc创建并存储一个新的)我认为问题不在于string.format 结果是: 格式为108毫秒 公开赛1416毫秒 5176毫秒用于执行 整个过程是6891毫秒 运行这个,非常简单的测试
namespace ConsoleApplication1
{
class Program
{
private static string DataIP;
private static string Database;
private static string IntanceID;
static void Main(string[] args)
{
DataIP = @"FREDOU-PC\SQLEXPRESS"; Database = "testing"; IntanceID = "123";
int count = 0;
System.Diagnostics.Stopwatch swWholeThing = System.Diagnostics.Stopwatch.StartNew();
System.Diagnostics.Stopwatch swFormat = new System.Diagnostics.Stopwatch();
System.Diagnostics.Stopwatch swOpen = new System.Diagnostics.Stopwatch();
System.Diagnostics.Stopwatch swExecute = new System.Diagnostics.Stopwatch();
for (int i = 0; i < 100000; ++i)
{
using (System.Data.SqlClient.SqlConnection sqlconn = new System.Data.SqlClient.SqlConnection(SqlConnectionString(ref swFormat)))
{
using (System.Data.SqlClient.SqlCommand sqlcmd = new System.Data.SqlClient.SqlCommand("dbo.counttable1", sqlconn))
{
sqlcmd.CommandType = System.Data.CommandType.StoredProcedure;
sqlcmd.Parameters.Clear();
swOpen.Start();
sqlconn.Open();
swOpen.Stop();
swExecute.Start();
using (System.Data.SqlClient.SqlDataReader sqlDR = sqlcmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection))
{
if (sqlDR.Read())
count += sqlDR.GetInt32(0);
}
swExecute.Stop();
}
}
}
swWholeThing.Stop();
System.Console.WriteLine("swFormat: " + swFormat.ElapsedMilliseconds);
System.Console.WriteLine("swOpen: " + swOpen.ElapsedMilliseconds);
System.Console.WriteLine("swExecute: " + swExecute.ElapsedMilliseconds);
System.Console.WriteLine("swWholeThing: " + swWholeThing.ElapsedMilliseconds + " " + count);
System.Console.ReadKey();
}
public static string SqlConnectionString(ref System.Diagnostics.Stopwatch swFormat)
{
swFormat.Start();
var str = string.Format("Data Source={0};Initial Catalog={1};Integrated Security=True;Application Name={2};Asynchronous Processing=true;MultipleActiveResultSets=true;Max Pool Size=524;Pooling=true;",
DataIP, Database, IntanceID);
swFormat.Stop();
return str;
}
}
}
dbo.table_1
USE [testing]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table_1](
[id] [int] NOT NULL,
CONSTRAINT [PK_Table_1] PRIMARY KEY CLUSTERED
(
[id] 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
内容:
insert into dbo.Table_1 (id) values (1)
insert into dbo.Table_1 (id) values (2)
insert into dbo.Table_1 (id) values (3)
insert into dbo.Table_1 (id) values (4)
insert into dbo.Table_1 (id) values (5)
insert into dbo.Table_1 (id) values (6)
insert into dbo.Table_1 (id) values (7)
insert into dbo.Table_1 (id) values (8)
insert into dbo.Table_1 (id) values (9)
insert into dbo.Table_1 (id) values (10)
我认为问题不在于string.format 结果是: 格式为108毫秒 公开赛1416毫秒 5176毫秒用于执行 整个过程是6891毫秒 运行这个,非常简单的测试
namespace ConsoleApplication1
{
class Program
{
private static string DataIP;
private static string Database;
private static string IntanceID;
static void Main(string[] args)
{
DataIP = @"FREDOU-PC\SQLEXPRESS"; Database = "testing"; IntanceID = "123";
int count = 0;
System.Diagnostics.Stopwatch swWholeThing = System.Diagnostics.Stopwatch.StartNew();
System.Diagnostics.Stopwatch swFormat = new System.Diagnostics.Stopwatch();
System.Diagnostics.Stopwatch swOpen = new System.Diagnostics.Stopwatch();
System.Diagnostics.Stopwatch swExecute = new System.Diagnostics.Stopwatch();
for (int i = 0; i < 100000; ++i)
{
using (System.Data.SqlClient.SqlConnection sqlconn = new System.Data.SqlClient.SqlConnection(SqlConnectionString(ref swFormat)))
{
using (System.Data.SqlClient.SqlCommand sqlcmd = new System.Data.SqlClient.SqlCommand("dbo.counttable1", sqlconn))
{
sqlcmd.CommandType = System.Data.CommandType.StoredProcedure;
sqlcmd.Parameters.Clear();
swOpen.Start();
sqlconn.Open();
swOpen.Stop();
swExecute.Start();
using (System.Data.SqlClient.SqlDataReader sqlDR = sqlcmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection))
{
if (sqlDR.Read())
count += sqlDR.GetInt32(0);
}
swExecute.Stop();
}
}
}
swWholeThing.Stop();
System.Console.WriteLine("swFormat: " + swFormat.ElapsedMilliseconds);
System.Console.WriteLine("swOpen: " + swOpen.ElapsedMilliseconds);
System.Console.WriteLine("swExecute: " + swExecute.ElapsedMilliseconds);
System.Console.WriteLine("swWholeThing: " + swWholeThing.ElapsedMilliseconds + " " + count);
System.Console.ReadKey();
}
public static string SqlConnectionString(ref System.Diagnostics.Stopwatch swFormat)
{
swFormat.Start();
var str = string.Format("Data Source={0};Initial Catalog={1};Integrated Security=True;Application Name={2};Asynchronous Processing=true;MultipleActiveResultSets=true;Max Pool Size=524;Pooling=true;",
DataIP, Database, IntanceID);
swFormat.Stop();
return str;
}
}
}
dbo.table_1
USE [testing]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table_1](
[id] [int] NOT NULL,
CONSTRAINT [PK_Table_1] PRIMARY KEY CLUSTERED
(
[id] 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
内容:
insert into dbo.Table_1 (id) values (1)
insert into dbo.Table_1 (id) values (2)
insert into dbo.Table_1 (id) values (3)
insert into dbo.Table_1 (id) values (4)
insert into dbo.Table_1 (id) values (5)
insert into dbo.Table_1 (id) values (6)
insert into dbo.Table_1 (id) values (7)
insert into dbo.Table_1 (id) values (8)
insert into dbo.Table_1 (id) values (9)
insert into dbo.Table_1 (id) values (10)
如果要在循环中访问DataReader,那么应该在循环外找到索引,然后在循环内使用它们。您还可以更好地使用强类型ACCESOR。如果要在循环中访问DataReader,那么应该在循环外找到索引,然后在循环内使用它们。您还可以更好地使用强类型ACCESOR