SqlParameter居然不如字符串拼接效率高,很怪的问题。

时间:2021-11-28 22:15:31
直接上代码,
别一个贴子上有详细说明
http://topic.csdn.net/u/20120116/14/4cbcea4c-4b2a-47dd-989c-bb5ebf57ad2a.html?seed=525050463&r=77321509#r_77321509

 public DataSet GetRegInfoGameList(DateTime BeginTime, DateTime EndTime)
  {

// #region 用字符串拼接 测试结果,这个正常
// StringBuilder strSql = new StringBuilder();
// strSql.Append(@"
//select GameKey as [GameKey],max(GameName) as [GameName],COUNT(1) as [TCount],
//sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMoney) as [ClearingMoney],sum(RegInfo.ReturnMoney) as [ReturnMoney]
//from RegInfo ");
// strSql.Append("where PostTime between '" + BeginTime.ToString() + "' and '" + EndTime .ToString()+ "' ");   
// return DbHelperSQL.Query(strSql.ToString());
// #endregion


  #region 用SqlParameter测试 测试结果,这个报超时错误,但放在查询分析器里不报超时
  StringBuilder strSql = new StringBuilder();
strSql.Append(@"
select GameKey as [GameKey],max(GameName) as [GameName],COUNT(1) as [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMoney) as [ClearingMoney],sum(RegInfo.ReturnMoney) as [ReturnMoney]
from RegInfo ");
strSql.Append("where PostTime between @BeginTime and @EndTime ");
SqlParameter[] parameters = {
  new SqlParameter("@BeginTime", SqlDbType.DateTime),
  new SqlParameter("@EndTime", SqlDbType.DateTime)};
parameters[0].Value = BeginTime;
parameters[1].Value = EndTime;
return DbHelperSQL.Query(strSql.ToString(), parameters);

  #endregion

  }

26 个解决方案

#1


DbHelperSQL这个类是如何写的?
从代码上看,这2种写法完全可行,都不会有问题。你也可以监视SQLSERVER的SQL语句执行情况,看看最终执行的是什么语句。

#2


引用 1 楼 qldsrx 的回复:
DbHelperSQL这个类是如何写的?
从代码上看,这2种写法完全可行,都不会有问题。你也可以监视SQLSERVER的SQL语句执行情况,看看最终执行的是什么语句。


监视了Sqlserver的执行情况,语句都是正常的,在查询分析器里两种执行都可以。

但第二种通过c#调用的时候报超时。


#3


直接拼接字符串就是硬编码肯定效率高.
第二个程序端会进行数据有效性的验证.
直接拼接就相当于直接在数据库执行了.

#4


 我估计可能是因为转换DateTime时引起的,但我传进去的类型也是DateTime类型的值啊。

#5


引用 4 楼 x2670316290 的回复:
 我估计可能是因为转换DateTime时引起的,但我传进去的类型也是DateTime类型的值啊。


前面的程序没问题,你用sql server profiler 跟一下,把两个执行的最终的sql贴出来

#6


其实不用贴也能看出问题了
第一种方法,也就是直接拼接的最终执行的是between '起始时间' and '结束时间'
很显然已经是字符类型了,不是datetime类型
第二个执行的结果是...,N'@BeginTime datetime,@EndTime datetime',@BeginTime='1996-01-01 00:00:00',@EndTime='2010-01-01 00:00:00'
是日期格式了

要确定是不是这一个问题
可以在查询分析器里面写两个sql语句就知道了
declare @EndTime varchar(20),@BeginTime varchar(20)
set @BeginTime=''
set @EndTime=''

sql语句。。。。


然后
declare @EndTime datetime,@BeginTime datetime
set @BeginTime=''
set @EndTime=''

sql语句。。。。。


你比较下这两个有产生的效果是不是和你写的两个程序的一样,或者看执行计划

就知道是什么问题了

#7



监听出来的代码是这样的
exec sp_executesql N'
select GameKey  as  [GameKey],max(GameName) as [GameName],COUNT(1) as  [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMoney) as [ClearingMoney],sum(RegInfo.ReturnMoney) as [ReturnMoney]
from   RegInfo  
group by RegInfo.GameKey order by RegInfo.GameKey ',
N'@BeginTime datetime,
@EndTime datetime',@BeginTime='2012-01-01 00:00:00',
@EndTime='2012-01-16 00:00:00'

#8


引用 7 楼 x2670316290 的回复:
监听出来的代码是这样的
exec sp_executesql N'
select GameKey  as  [GameKey],max(GameName) as [GameName],COUNT(1) as  [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMoney) as [ClearingMoney],sum……


你这个是用参数的,不用参数的呢?

#9


引用 7 楼 x2670316290 的回复:
监听出来的代码是这样的
exec sp_executesql N'
select GameKey  as  [GameKey],max(GameName) as [GameName],COUNT(1) as  [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMoney) as [ClearingMoney],sum……


这个在查询分析器里执行是正常的。

#10


上面这个复制错代码了,这个是测试不加where的时候的跟踪

#11


where条件呢?

#12


引用 8 楼 jiangshun 的回复:
引用 7 楼 x2670316290 的回复:
监听出来的代码是这样的
exec sp_executesql N'
select GameKey  as  [GameKey],max(GameName) as [GameName],COUNT(1) as  [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMon……


不用参数的是正常的,不报错误超时。如果是拼接的时候报超时,我直接就改成用参数的了。现在是反起来了。

#13


declare @BeginTime varchar(20),@EndTime varchar(20)
set @BeginTime='2012-01-01 00:00:00'
set @EndTime='2012-01-16 00:00:00'
select GameKey as [GameKey],max(GameName) as [GameName],COUNT(1) as [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMoney) as [ClearingMoney],sum(RegInfo.ReturnMoney) as [ReturnMoney]
from RegInfo  
where PostTime between @BeginTime and @EndTime
group by RegInfo.GameKey order by RegInfo.GameKey 


declare @BeginTime datetime,@EndTime datetime
set @BeginTime='2012-01-01 00:00:00'
set @EndTime='2012-01-16 00:00:00'
select GameKey as [GameKey],max(GameName) as [GameName],COUNT(1) as [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMoney) as [ClearingMoney],sum(RegInfo.ReturnMoney) as [ReturnMoney]
from RegInfo  
where PostTime between @BeginTime and @EndTime
group by RegInfo.GameKey order by RegInfo.GameKey 


楼主你看下这两个查询,结果是不是一个快一个慢?

#14


引用 11 楼 jiangshun 的回复:
where条件呢?



exec sp_executesql N'
select GameKey  as  [GameKey],max(GameName) as [GameName],COUNT(1) as  [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMoney) as [ClearingMoney],sum(RegInfo.ReturnMoney) as [ReturnMoney]
from   RegInfo 
where  RegInfo.PostTime between @BeginTime and @EndTime
group by RegInfo.GameKey order by RegInfo.GameKey ',
N'@BeginTime datetime,
@EndTime datetime',@BeginTime='2012-01-01 00:00:00',
@EndTime='2012-01-16 00:00:00'

#15


能把你DBHelper 中 DbHelperSQL.Query(string sql,SqlParameters[] parameters)的方法贴出来看一下么?

#16


引用 13 楼 jiangshun 的回复:
SQL code
declare @BeginTime varchar(20),@EndTime varchar(20)
set @BeginTime='2012-01-01 00:00:00'
set @EndTime='2012-01-16 00:00:00'
select GameKey as [GameKey],max(GameName) as [GameName],COUNT(1) ……


在查询分析器里执行时间差不多,都显示是2秒,因为这个表有30多万条数据。

#17


引用 15 楼 hualilihua 的回复:
能把你DBHelper 中 DbHelperSQL.Query(string sql,SqlParameters[] parameters)的方法贴出来看一下么?


  /// <summary>
        /// 执行查询语句,返回DataSet
        /// </summary>
        /// <param name="SQLString">查询语句</param>
        /// <returns>DataSet</returns>
        public static DataSet Query(string SQLString, params SqlParameter[] cmdParms)
        {
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                SqlCommand cmd = new SqlCommand();
                PrepareCommand(cmd, connection, null, SQLString, cmdParms);
                using (SqlDataAdapter da = new SqlDataAdapter(cmd))
                {
                    DataSet ds = new DataSet();
                    try
                    {
                        da.Fill(ds, "ds");
                        cmd.Parameters.Clear();
                    }
                    catch (System.Data.SqlClient.SqlException ex)
                    {
                        throw new Exception(ex.Message);
                    }
                    return ds;
                }
            }
        }


        private static void PrepareCommand(SqlCommand cmd, SqlConnection conn, SqlTransaction trans, string cmdText, SqlParameter[] cmdParms)
        {
            if (conn.State != ConnectionState.Open)
                conn.Open();
            cmd.Connection = conn;
            cmd.CommandText = cmdText;
            if (trans != null)
                cmd.Transaction = trans; 
            cmd.CommandType = CommandType.Text;//cmdType;
            if (cmdParms != null)
            {


                foreach (SqlParameter parameter in cmdParms)
                {
                    if ((parameter.Direction == ParameterDirection.InputOutput || parameter.Direction == ParameterDirection.Input) &&
                        (parameter.Value == null))
                    {
                        parameter.Value = DBNull.Value;
                    }
                    cmd.Parameters.Add(parameter);
                }
            }
        }



#18


引用 15 楼 hualilihua 的回复:
能把你DBHelper 中 DbHelperSQL.Query(string sql,SqlParameters[] parameters)的方法贴出来看一下么?


这个是用的现成的代码,这个应该没有问题。

我在想会不会是外部环境引起的?

#19


引用 18 楼 x2670316290 的回复:
引用 15 楼 hualilihua 的回复:

能把你DBHelper 中 DbHelperSQL.Query(string sql,SqlParameters[] parameters)的方法贴出来看一下么?


这个是用的现成的代码,这个应该没有问题。

我在想会不会是外部环境引起的?


如果类型解释不了,还真找不到合适的解释了

#20


没问题啊 我测试了下 不过就几条数据而已

#21


楼主 你看一下 这个SqlParameter的作用就知道了 

他的用处不在效率上 啊。。

在安全和数据检测上
http://topic.csdn.net/u/20070320/16/1fb031d7-9036-4dbc-9ca0-6d9301dabbc0.html
我是学java的  估计你这个也就是在发现 原来直接封装SQL字符串在某些情况下 可以被注入 所以就写了个封装类

SqlParameter居然不如字符串拼接效率高,很怪的问题。

#22


检查2种查询给的条件是否一致,查询模拟情况是否一致。应该是其它地方造成的问题,代码本身没语法错误,也不会造成任何超时的可能性。

#23


你先查询前10行看看,加个top 10,看看是否超时。

#24


SqlParameter,为了是防止SQL注入,不会提升效率,反而降低一点点效率的。

#25


呵呵 参数 性我者 得永生

字符串 传入 
在 转换 成 时间
知道为什么 吗

你 的 索引 出问题了 
急的话 就这样干,破坏索引查询,

有时 索引 就是 个大杀器 双刃刀 可伤人 可伤己

不急 找出 涉及 索引 删除 重建

#26


呵呵 参数 性我者 得永生

字符串 传入 
在 转换 成 时间
知道为什么 吗

你 的 索引 出问题了 
急的话 就这样干,破坏索引查询,

有时 索引 就是 个大杀器 双刃刀 可伤人 可伤己

不急 找出 涉及 索引 删除 重建

#1


DbHelperSQL这个类是如何写的?
从代码上看,这2种写法完全可行,都不会有问题。你也可以监视SQLSERVER的SQL语句执行情况,看看最终执行的是什么语句。

#2


引用 1 楼 qldsrx 的回复:
DbHelperSQL这个类是如何写的?
从代码上看,这2种写法完全可行,都不会有问题。你也可以监视SQLSERVER的SQL语句执行情况,看看最终执行的是什么语句。


监视了Sqlserver的执行情况,语句都是正常的,在查询分析器里两种执行都可以。

但第二种通过c#调用的时候报超时。


#3


直接拼接字符串就是硬编码肯定效率高.
第二个程序端会进行数据有效性的验证.
直接拼接就相当于直接在数据库执行了.

#4


 我估计可能是因为转换DateTime时引起的,但我传进去的类型也是DateTime类型的值啊。

#5


引用 4 楼 x2670316290 的回复:
 我估计可能是因为转换DateTime时引起的,但我传进去的类型也是DateTime类型的值啊。


前面的程序没问题,你用sql server profiler 跟一下,把两个执行的最终的sql贴出来

#6


其实不用贴也能看出问题了
第一种方法,也就是直接拼接的最终执行的是between '起始时间' and '结束时间'
很显然已经是字符类型了,不是datetime类型
第二个执行的结果是...,N'@BeginTime datetime,@EndTime datetime',@BeginTime='1996-01-01 00:00:00',@EndTime='2010-01-01 00:00:00'
是日期格式了

要确定是不是这一个问题
可以在查询分析器里面写两个sql语句就知道了
declare @EndTime varchar(20),@BeginTime varchar(20)
set @BeginTime=''
set @EndTime=''

sql语句。。。。


然后
declare @EndTime datetime,@BeginTime datetime
set @BeginTime=''
set @EndTime=''

sql语句。。。。。


你比较下这两个有产生的效果是不是和你写的两个程序的一样,或者看执行计划

就知道是什么问题了

#7



监听出来的代码是这样的
exec sp_executesql N'
select GameKey  as  [GameKey],max(GameName) as [GameName],COUNT(1) as  [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMoney) as [ClearingMoney],sum(RegInfo.ReturnMoney) as [ReturnMoney]
from   RegInfo  
group by RegInfo.GameKey order by RegInfo.GameKey ',
N'@BeginTime datetime,
@EndTime datetime',@BeginTime='2012-01-01 00:00:00',
@EndTime='2012-01-16 00:00:00'

#8


引用 7 楼 x2670316290 的回复:
监听出来的代码是这样的
exec sp_executesql N'
select GameKey  as  [GameKey],max(GameName) as [GameName],COUNT(1) as  [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMoney) as [ClearingMoney],sum……


你这个是用参数的,不用参数的呢?

#9


引用 7 楼 x2670316290 的回复:
监听出来的代码是这样的
exec sp_executesql N'
select GameKey  as  [GameKey],max(GameName) as [GameName],COUNT(1) as  [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMoney) as [ClearingMoney],sum……


这个在查询分析器里执行是正常的。

#10


上面这个复制错代码了,这个是测试不加where的时候的跟踪

#11


where条件呢?

#12


引用 8 楼 jiangshun 的回复:
引用 7 楼 x2670316290 的回复:
监听出来的代码是这样的
exec sp_executesql N'
select GameKey  as  [GameKey],max(GameName) as [GameName],COUNT(1) as  [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMon……


不用参数的是正常的,不报错误超时。如果是拼接的时候报超时,我直接就改成用参数的了。现在是反起来了。

#13


declare @BeginTime varchar(20),@EndTime varchar(20)
set @BeginTime='2012-01-01 00:00:00'
set @EndTime='2012-01-16 00:00:00'
select GameKey as [GameKey],max(GameName) as [GameName],COUNT(1) as [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMoney) as [ClearingMoney],sum(RegInfo.ReturnMoney) as [ReturnMoney]
from RegInfo  
where PostTime between @BeginTime and @EndTime
group by RegInfo.GameKey order by RegInfo.GameKey 


declare @BeginTime datetime,@EndTime datetime
set @BeginTime='2012-01-01 00:00:00'
set @EndTime='2012-01-16 00:00:00'
select GameKey as [GameKey],max(GameName) as [GameName],COUNT(1) as [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMoney) as [ClearingMoney],sum(RegInfo.ReturnMoney) as [ReturnMoney]
from RegInfo  
where PostTime between @BeginTime and @EndTime
group by RegInfo.GameKey order by RegInfo.GameKey 


楼主你看下这两个查询,结果是不是一个快一个慢?

#14


引用 11 楼 jiangshun 的回复:
where条件呢?



exec sp_executesql N'
select GameKey  as  [GameKey],max(GameName) as [GameName],COUNT(1) as  [TCount],
sum(RegInfo.OkMoney) as [TMoney],sum(RegInfo.ClearingMoney) as [ClearingMoney],sum(RegInfo.ReturnMoney) as [ReturnMoney]
from   RegInfo 
where  RegInfo.PostTime between @BeginTime and @EndTime
group by RegInfo.GameKey order by RegInfo.GameKey ',
N'@BeginTime datetime,
@EndTime datetime',@BeginTime='2012-01-01 00:00:00',
@EndTime='2012-01-16 00:00:00'

#15


能把你DBHelper 中 DbHelperSQL.Query(string sql,SqlParameters[] parameters)的方法贴出来看一下么?

#16


引用 13 楼 jiangshun 的回复:
SQL code
declare @BeginTime varchar(20),@EndTime varchar(20)
set @BeginTime='2012-01-01 00:00:00'
set @EndTime='2012-01-16 00:00:00'
select GameKey as [GameKey],max(GameName) as [GameName],COUNT(1) ……


在查询分析器里执行时间差不多,都显示是2秒,因为这个表有30多万条数据。

#17


引用 15 楼 hualilihua 的回复:
能把你DBHelper 中 DbHelperSQL.Query(string sql,SqlParameters[] parameters)的方法贴出来看一下么?


  /// <summary>
        /// 执行查询语句,返回DataSet
        /// </summary>
        /// <param name="SQLString">查询语句</param>
        /// <returns>DataSet</returns>
        public static DataSet Query(string SQLString, params SqlParameter[] cmdParms)
        {
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                SqlCommand cmd = new SqlCommand();
                PrepareCommand(cmd, connection, null, SQLString, cmdParms);
                using (SqlDataAdapter da = new SqlDataAdapter(cmd))
                {
                    DataSet ds = new DataSet();
                    try
                    {
                        da.Fill(ds, "ds");
                        cmd.Parameters.Clear();
                    }
                    catch (System.Data.SqlClient.SqlException ex)
                    {
                        throw new Exception(ex.Message);
                    }
                    return ds;
                }
            }
        }


        private static void PrepareCommand(SqlCommand cmd, SqlConnection conn, SqlTransaction trans, string cmdText, SqlParameter[] cmdParms)
        {
            if (conn.State != ConnectionState.Open)
                conn.Open();
            cmd.Connection = conn;
            cmd.CommandText = cmdText;
            if (trans != null)
                cmd.Transaction = trans; 
            cmd.CommandType = CommandType.Text;//cmdType;
            if (cmdParms != null)
            {


                foreach (SqlParameter parameter in cmdParms)
                {
                    if ((parameter.Direction == ParameterDirection.InputOutput || parameter.Direction == ParameterDirection.Input) &&
                        (parameter.Value == null))
                    {
                        parameter.Value = DBNull.Value;
                    }
                    cmd.Parameters.Add(parameter);
                }
            }
        }



#18


引用 15 楼 hualilihua 的回复:
能把你DBHelper 中 DbHelperSQL.Query(string sql,SqlParameters[] parameters)的方法贴出来看一下么?


这个是用的现成的代码,这个应该没有问题。

我在想会不会是外部环境引起的?

#19


引用 18 楼 x2670316290 的回复:
引用 15 楼 hualilihua 的回复:

能把你DBHelper 中 DbHelperSQL.Query(string sql,SqlParameters[] parameters)的方法贴出来看一下么?


这个是用的现成的代码,这个应该没有问题。

我在想会不会是外部环境引起的?


如果类型解释不了,还真找不到合适的解释了

#20


没问题啊 我测试了下 不过就几条数据而已

#21


楼主 你看一下 这个SqlParameter的作用就知道了 

他的用处不在效率上 啊。。

在安全和数据检测上
http://topic.csdn.net/u/20070320/16/1fb031d7-9036-4dbc-9ca0-6d9301dabbc0.html
我是学java的  估计你这个也就是在发现 原来直接封装SQL字符串在某些情况下 可以被注入 所以就写了个封装类

SqlParameter居然不如字符串拼接效率高,很怪的问题。

#22


检查2种查询给的条件是否一致,查询模拟情况是否一致。应该是其它地方造成的问题,代码本身没语法错误,也不会造成任何超时的可能性。

#23


你先查询前10行看看,加个top 10,看看是否超时。

#24


SqlParameter,为了是防止SQL注入,不会提升效率,反而降低一点点效率的。

#25


呵呵 参数 性我者 得永生

字符串 传入 
在 转换 成 时间
知道为什么 吗

你 的 索引 出问题了 
急的话 就这样干,破坏索引查询,

有时 索引 就是 个大杀器 双刃刀 可伤人 可伤己

不急 找出 涉及 索引 删除 重建

#26


呵呵 参数 性我者 得永生

字符串 传入 
在 转换 成 时间
知道为什么 吗

你 的 索引 出问题了 
急的话 就这样干,破坏索引查询,

有时 索引 就是 个大杀器 双刃刀 可伤人 可伤己

不急 找出 涉及 索引 删除 重建