根据标准,SQLDataReader的速度太慢

时间:2015-04-10 13:47:13

标签: c# sql asp.net data-binding sqldatareader

我使用SQLDataReader在asp.net页面上填充GridView(GridView1)。 SQLDataReader在C#Codebehind中设置自己,如下所示:

        string MySQLString;
        MySQLString = "SELECT * FROM [vw_Report_Latest_v3_1] WHERE [FKID_Contract]=@Contract";
        if ((string)Session["TSAreaString"] != "") { MySQLString = MySQLString + " AND [L1_Name]=@PA1"; }
        if ((string)Session["TSSiteString"] != "") { MySQLString = MySQLString + " AND [L2_Name]=@PA2"; }
        if ((string)Session["TSFeatureString"] != "") { MySQLString = MySQLString + " AND [L3_Name]=@PA3"; }
        if ((string)Session["TSS1"] != "") { MySQLString = MySQLString + " AND [Spare1]=@S1"; }
        if ((string)Session["TSS2"] != "") { MySQLString = MySQLString + " AND [Spare2]=@S2"; }
        if ((string)Session["TSS3"] != "") { MySQLString = MySQLString + " AND [Spare3]=@S3"; }
        if ((string)Session["TSS4"] != "") { MySQLString = MySQLString + " AND [Spare4]=@S4"; }
        if ((string)Session["TSS5"] != "") { MySQLString = MySQLString + " AND [Spare5]=@S5"; }
        if ((string)Session["TSTaskString"] != "") { MySQLString = MySQLString + " AND [Operation_Name]=@PA4"; }
        if ((string)Session["TSTeamString"] != "") { MySQLString = MySQLString + " AND [Team_Name]=@Team"; }
        //finish
        MySQLString = MySQLString + " ORDER BY [OperationOrder], [L1_Name], [L2_Name], [L3_Name], [Operation_Name], [Team_Name]";
        try
        {
            Conn.Open();
            SqlCommand Cmd = new SqlCommand(MySQLString, Conn);
            Cmd.Parameters.AddWithValue("@Contract", Convert.ToInt32(invCID.Text));
            if ((string)Session["TSAreaString"] != "") { Cmd.Parameters.AddWithValue("@PA1", (string)Session["TSAreaString"]); }
            if ((string)Session["TSSiteString"] != "") { Cmd.Parameters.AddWithValue("@PA2", (string)Session["TSSiteString"]); }
            if ((string)Session["TSFeatureString"] != "") { Cmd.Parameters.AddWithValue("@PA3", (string)Session["TSFeatureString"]); }
            if ((string)Session["TSS1"] != "") { Cmd.Parameters.AddWithValue("@S1", (string)Session["TSS1"]); }
            if ((string)Session["TSS2"] != "") { Cmd.Parameters.AddWithValue("@S2", (string)Session["TSS2"]); }
            if ((string)Session["TSS3"] != "") { Cmd.Parameters.AddWithValue("@S3", (string)Session["TSS3"]); }
            if ((string)Session["TSS4"] != "") { Cmd.Parameters.AddWithValue("@S4", (string)Session["TSS4"]); }
            if ((string)Session["TSS5"] != "") { Cmd.Parameters.AddWithValue("@S5", (string)Session["TSS5"]); }
            if ((string)Session["TSTaskString"] != "") { Cmd.Parameters.AddWithValue("@PA4", (string)Session["TSTaskString"]); }
            if ((string)Session["TSTeamString"] != "") { Cmd.Parameters.AddWithValue("@Team", (string)Session["TSTeamString"]); }
            Cmd.Connection = Conn;
            SqlDataReader reader = Cmd.ExecuteReader(CommandBehavior.CloseConnection);
            GridView1.DataSource = reader;
            GridView1.DataBind();
        }
        finally
        {
            if (Conn != null) { Conn.Close(); }
        }

这给了我严重的问题。例如,如果我们将L1_Name(通过给TSAreaString赋值)设置为" Town",它将显示L1_Name为" Town"的所有内容。哪个好,花花公子。需要几秒钟,因为它是一个大城市。

但是,如果我们将L1_Name设置为" Town"和TSS3(在这个例子中)到"郡",然后它需要更长时间 - 有时超过一分钟 - 尽管它检索相同数量的记录,或者有时更少。

不幸的是我们必须把它放进去 - 我们不能只搜索#34; Town"我们必须搜索" Town"和"县"由于我们的客户强加。

这是从--vw_Report_Latest_v3_1运行的视图 - 运行绝对正常。即使使用上述标准,也没有问题。这两种方案 - Town和Town AND County,仅通过SQL Server 2008在View上花费的时间相同。

我很确定它是以某种方式阅读/装订。

3 个答案:

答案 0 :(得分:1)

您可以做几个改进领域。

  • 你应该使用StringBuilder而不是string = string +“”;它的效率更高
  • 而不是!=“”,我建议!string.IsNullOrEmpty((string)Session [“”])。这样它会捕获null,string.empty和“”
  • (个人喜好)不要害怕空白。将if语句放在同一行......很难阅读。
  • 好的工作包装内容{}如果你不这样做,这是下一个人的噩梦
  • 分离图层是一个好主意(如@mason提到的那样)。我个人有一个数据层来存放查询。没有逻辑。然后是业务层或类层。它包含了逻辑。清理,验证等......然后将代码传递给类层。
  • 我看到两种类型的业务层。有真正的对象风格。数据层变为数据表然后它被加载到类中。查看POCO以了解相关信息。另一个,这是我几年前开始的地方,是一个层系统。每个方法都是自包含的,只是将东西传递给数据层,如果它是一个select,则返回一个数据表。
  • 提取出与数据库联系的代码。 (见底部的代码)
你提到了一个观点。检查索引。因为这是mysql ...我不知道hwo这样做但是当使用Microsoft SQL时,你可以使用什么称为估计执行路径。因此,您可以将select语句放在MSSMS软件中,而不是执行,您可以单击“显示估计执行路径”按钮,该按钮将为索引等提供建议。

以下是您的数据层的外观以及它如何使用连接器(下一个代码块)

private MySQLConnector _MySQL = null;
protected MySQLConnector MySQL
{
   get
   {
      if (_MySQL == null)
      {
         _MySQL = new MySQLConnector();
      }
      return _MySQL;
   }
}

public void Update(int programId, int LocationId, string Name, string modifiedBy)
   {
   List<MySqlParameter> parameterList = new List<MySqlParameter>();

   parameterList.Add(new MySqlParameter("ProgramID", programId));
   parameterList.Add(new MySqlParameter("LocationId", LocationId));
   parameterList.Add(new MySqlParameter("Name", Name));
   if (!string.IsNullOrEmpty(modifiedBy))
   {
      parameterList.Add(new MySqlParameter("ModifiedBy", modifiedBy));
   }
   else
   {
      parameterList.Add(new MySqlParameter("ModifiedBy", DBNull.Value));
   }

   const string TheSql = @"
            UPDATE ProgramLocation
            SET
           Name = @Name,
               ModifiedOn = GETDATE(),
               ModifiedBy = @ModifiedBy
            WHERE
        ProgramID = @ProgramID
        AND LocationId = @LocationId";

   MySQL.ExecuteNonQuerySql(TheSql, parameterList);
}

这是与数据库联系的代码。它有点过时了,您可能需要将其更改为用于联系MySQL数据库的软件包。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Configuration;
using System.Reflection;
using MySql.Data.MySqlClient;

namespace DEFINETHENameSpace
{
    public class MySQLConnector
    {
        private string connString = null;

        public string TheConnectionString
        {
            get
            {
                if (string.IsNullOrEmpty(connString))
                {
                    //  connString = ConfigurationManager.ConnectionStrings["MySQLConnection"].ConnectionString; 
                    throw new Exception("No Connection String Specified");
                }

                return connString;
            }

            set
            {
                connString = value;
            }
        }

        private Exception errorMessage;

        public Exception ErrorMessage
        {
            get
            {
                return errorMessage;
            }

            set
            {
                errorMessage = value;
            }
        }

        #region ExecuteNonQuery
        /// <summary>
        /// THis will execute a non query, such as an insert statement
        /// </summary>
        /// <returns>1 for success, 0 for failed.</returns>
        /// <author>James 'Gates' R.</author>
        /// <createdate>8/20/2012</createdate>
        public int ExecuteNonQuery(string theSQLStatement)
        {
            int returnValue = 0;

            if (!string.IsNullOrEmpty(theSQLStatement))
            {
                MySqlConnection connection = new MySqlConnection(TheConnectionString);
                MySqlCommand command = connection.CreateCommand();

                try
                {
                    command.CommandText = theSQLStatement;
                    connection.Open();
                    command.ExecuteNonQuery();

                    //Success
                    returnValue = 1;
                }
                catch (Exception ex)
                {
                    returnValue = 0;
                    throw ex; //ErrorMessage = ex; 
                    // WriteToLog.Execute(ex.Message, EventLogEntryType.Error);
                }
                finally
                {
                    command.Dispose();
                    if (connection.State == System.Data.ConnectionState.Open)
                    {
                        connection.Close();
                    }

                    connection.Dispose();
                }
            }

            return returnValue;
        }

        /// <summary>
        /// THis will execute a non query, such as an insert statement
        /// </summary>
        /// <returns>1 for success, 0 for failed.</returns>
        /// <author>James 'Gates' R.</author>
        /// <createdate>8/20/2012</createdate>
        public int ExecuteNonQuery(string theSQLStatement, List<MySqlParameter> parameters)
        {
            if ((parameters != null) && (parameters.Count > 0))
            {
                return ExecuteNonQuery(theSQLStatement, parameters.ToArray());
            }
            else
            {
                return ExecuteNonQuery(theSQLStatement);
            }
        }

        /// <summary>
        /// THis will execute a non query, such as an insert statement
        /// </summary>
        /// <returns>1 for success, 0 for failed.</returns>
        /// <author>James 'Gates' R.</author>
        /// <createdate>8/20/2012</createdate>
        public int ExecuteNonQuery(string theSQLStatement, MySqlParameter[] parameters)
        {
            if ((parameters == null) || (parameters.Count() <= 0))
            {
                return ExecuteNonQuery(theSQLStatement);
            }

            int returnValue = 0;

            if (!string.IsNullOrEmpty(theSQLStatement))
            {
                MySqlConnection connection = new MySqlConnection(TheConnectionString);
                MySqlCommand command = connection.CreateCommand();

                try
                {
                    command.CommandText = theSQLStatement;
                    command.Parameters.AddRange(parameters);
                    connection.Open();
                    command.ExecuteNonQuery();

                    //Success
                    returnValue = 1;
                }
                catch (Exception ex)
                {
                    returnValue = 0;
                    throw ex; //ErrorMessage = ex; 
                    //WriteToLog.Execute(ex.Message, EventLogEntryType.Error);
                }
                finally
                {
                    command.Dispose();
                    if (connection.State == System.Data.ConnectionState.Open)
                    {
                        connection.Close();
                    }

                    connection.Dispose();
                }
            }

            return returnValue;
        }

        #endregion

        #region Execute
        /// <summary>
        /// THis will execute a query, such as an select statement
        /// </summary>
        /// <returns>Populated Datatable based on the sql select command.</returns>
        /// <author>James 'Gates' R.</author>
        /// <createdate>8/20/2012</createdate>
        public DataTable Execute(string theSQLStatement)
        {
            DataTable resultingDataTable = new DataTable();

            if (!string.IsNullOrEmpty(theSQLStatement))
            {
                MySqlConnection connection = new MySqlConnection(TheConnectionString);
                MySqlCommand command = connection.CreateCommand();

                try
                {
                    command.CommandText = theSQLStatement;
                    connection.Open();

                    MySqlDataAdapter dataAdapter = new MySqlDataAdapter(command.CommandText, connection);
                    dataAdapter.Fill(resultingDataTable);

                    //Success
                }
                catch (Exception ex)
                {
                    throw ex; //ErrorMessage = ex; 

                    //WriteToLog.Execute(ex.Message, EventLogEntryType.Error);
                }
                finally
                {
                    command.Dispose();
                    if (connection.State == System.Data.ConnectionState.Open)
                    {
                        connection.Close();
                    }

                    connection.Dispose();
                }
            }

            return resultingDataTable;
        }

        /// <summary>
        /// THis will execute a query, such as an select statement
        /// </summary>
        /// <returns>Populated Datatable based on the sql select command.</returns>
        /// <author>James 'Gates' R.</author>
        /// <createdate>8/20/2012</createdate>
        public DataTable Execute(string theSQLStatement, List<MySqlParameter> parameters)
        {

            if ((parameters != null) && (parameters.Count > 0))
            {
                return Execute(theSQLStatement, parameters.ToArray());
            }
            else
            {
                return Execute(theSQLStatement);
            }
        }

        /// <summary>
        /// THis will execute a query, such as an select statement
        /// </summary>
        /// <returns>Populated Datatable based on the sql select command.</returns>
        /// <author>James 'Gates' R.</author>
        /// <createdate>8/20/2012</createdate>
        public DataTable Execute(string theSQLStatement, MySqlParameter[] parameters)
        {
            if ((parameters == null) || (parameters.Count() <= 0))
            {
                return Execute(theSQLStatement);
            }

            DataTable resultingDataTable = new DataTable();

            if (!string.IsNullOrEmpty(theSQLStatement))
            {
                MySqlConnection connection = new MySqlConnection(TheConnectionString);
                MySqlCommand command = connection.CreateCommand();

                try
                {
                    command.CommandText = theSQLStatement;
                    connection.Open();

                    MySqlDataAdapter dataAdapter = new MySqlDataAdapter(command.CommandText, connection);
                    dataAdapter.SelectCommand.Parameters.AddRange(parameters);
                    dataAdapter.Fill(resultingDataTable);

                    //Success
                }
                catch (Exception ex)
                {
                    throw ex; //ErrorMessage = ex; 
                    //WriteToLog.Execute(ex.Message, EventLogEntryType.Error);
                }
                finally
                {
                    command.Dispose();
                    if (connection.State == System.Data.ConnectionState.Open)
                    {
                        connection.Close();
                    }

                    connection.Dispose();
                }
            }

            return resultingDataTable;
        }
    }
        #endregion
}

答案 1 :(得分:1)

您的SQL连接代码看起来不是问题,也不是GridView。尝试[在更高的范围内]获取会话变量并将其保存到Dictionary<string, object>Dictionary<string, string>(或某种方法)并从中检索您的值而不是点击浏览器每个值的会话(两次)。

您的视图/基础表的索引或不存在或麻烦。一定要检查这些。

要考虑的一些事项: 1.对于您尝试执行的操作,请创建一个不必让您自己构建SQL查询的存储过程。当你在未来增加复杂性时,你会感到头疼。例如,而不是:

if ((string)Session["TSAreaString"] != "") { MySQLString = MySQLString + " AND [L1_Name]=@PA1"; }

...您的存储过程可以非常轻松地使用COALESCE或ISNULL来实现相同的结果。

--parameter for stored procedure
@TSAreaString nvarchar(max) = NULL


SELECT v.* 
FROM View v
WHERE v.TSAreaString = COALESCE(@TSAreaString, v.TSAreaString)

(SQL Server语法)

如果你使用这种方法,你可以消除代码的上半部分并在下半部分做这样的事情:

Cmd.Parameters.AddWithValue("@Team", String.IsNullOrWhiteSpace((string)Session["TSTeamString"]) ? DBNull.Value : (string)Session["TSTeamString"]; 

但是,如果您要继续使用相同的方法:

  1. 使用StringBuilder而不是string。它是不可变的,如果你担心性能,它会因此而表现得更好。

  2. 将您的连接对象和命令对象包装到using子句中,以便暂时自动处理(长期,使您自己的类处理不同的数据库操作)。

    < / LI>
  3. 实际上这可能是你问题的一部分,但我不确定,因为我以前没办法完成。 不要将reader对象作为网格视图的DataSource,而是创建一个表示数据的类,并使用阅读器使用

    填充List<YourClass>

    while(reader.Read()) { YourList.Add(RetrieveYourClass(读取器)); }

  4. (^ SO不是因某种原因突出显示的代码)

答案 2 :(得分:0)

想出来,对于任何可能遇到类似情况的人来说。

基本上,正如上面的其他人所说的那样,一部分是 - 不要过多引用会话状态。相反,我做了我以前做的事情,因为我需要在页面上的标签中进行会话,只需从页面上的标签上阅读,而不是一直往返于会话。

然而,主要部分是改变SQL - 但只是一点点。而不是使用,说:

MySQLString = MySQLString + " AND [Spare1]=@S1";

我用过:

MySQLString = MySQLString + " AND ([Spare1] LIKE @S1)";

似乎封装了每个标准并且使用LIKE是关键 - 它现在在所有情况下都运行得非常快。