可以对我的GetEmails()方法进行哪些更改以减少数据库执行时间?

时间:2017-04-05 08:25:40

标签: c# sql-server database class instance

代码是这样的:

public class Email
{
    public string MailAddress {get;set;}
    public string MailOwner {get;set;}
    public int MailSended {get;set;}
    public int MailReceived {get;set;}
}

public class EmailList
{
    public List<Email> Items {get; private set;}
    private IDBConnection _connection;


    public EmailList(IDBConnection connection)
    {
        _connection = connection;
    }

    public List<Email> GetEmails(int customerId)
    {
        var emailList = new List<Email>();
        var sql = "SELECT * FROM EmailsAddress WHERE Id = '" + customerId + "'";

        using (var ObjectToAccessDatabaseAndStoreResultsIntoDataTable = new ObjectToObtainDbResultsIntoDataTable(_connection, sql))
        {
            foreach(DataRow row in  ObjectToAccessDatabaseAndStoreResultsIntoDataTable.Datatable)
            {
                var email = new Email{
                MailAddress = Convert.ToString(row["MailAddress"]);
                MailOwner = Convert.ToString(row["MailOwner"]);
                MailSended = Convert.ToInt32(row["MailSended"]);
                MailReceived = Convert.ToInt32(row["MailReceived"]);
            }

            emailList.Add(email);
        }       
        return emailList;
    }
}

当多次调用GetEmails()来检索邮件地址时,对于2000个客户,返回时需要很长时间。使用SQL Server Profiler,我发现大部分时间都是GetEmails()例程。

为什么GetEmails()例程需要这么长时间?我正在使用SQL Server。

3 个答案:

答案 0 :(得分:2)

  1. 您的EmailsAddress表中的Id列是否在此列上有索引?如果没有,添加一个将加快速度。

  2. 您总是应该使用参数化查询而不是字符串连接 - 它允许数据库优化您的查询,更重要的是,它可以保护您免受SQL注入攻击(尽管在您的情况下与整数类型不相关)

     var command =
        new SqlCommand("SELECT * FROM EmailsAddress WHERE Id = @Id;", db);
    command.Parameters.AddWithValue("@Id", yourTextValue);
    command.ExecuteQuery();
    
  3. Patrick Hofman所说的是,在查询客户时,通过对ID进行分组或使用联接来为您的客户提供服务将会更有效率。

  4. /编辑:这是一个询问多个ID的查询示例:

    var command =
        new SqlCommand("SELECT * FROM EmailsAddress WHERE Id IN (@Id1,@Id2,@Id3);", db);
    command.Parameters.AddWithValue("@Id1", 1);
    command.Parameters.AddWithValue("@Id2", 54);
    command.Parameters.AddWithValue("@Id2", 96);
    command.ExecuteReader();
    

    或者,忽略我自己的使用参数的建议:

    var sql = "SELECT * FROM EmailsAddress WHERE Id IN (1,54,96)";
    

    在循环中执行此操作的示例,参数:

            var ids = new int[] { 1, 95, 46, 93, 98, 77 };
            var isFirst = true;
            var commandBuilder = new StringBuilder("SELECT * FROM EmailsAddress WHERE Id IN (");
            var command = new SqlCommand("");
            for (var i = 0;i<ids.Length;i++)
            {
                if (!isFirst) commandBuilder.Append(",");
                else isFirst = false;
                var paramName = "@Id" + i;
                commandBuilder.Append(paramName);
                command.Parameters.AddWithValue(paramName, ids[i]);
            }
            commandBuilder.Append(")");
            command.CommandText = commandBuilder.ToString();
            command.ExecuteReader();
    
            // Read your result
    

答案 1 :(得分:1)

  

你能找到问题所在吗?

是的,您正在向数据库发送2000个SQL语句,该数据库必须逐个解析并执行它们,而在这种情况下,一个SQL语句就足够了。

您可以做什么,具体取决于数据库的大小:

  • 一次加载所有记录。将它们存储在缓存对象中,然后从该缓存中回答。当存在大量行并且您只打算获得一小组记录时,这可能是一个问题;
  • 一次加载多个客户。如果您不想立即获取整个表格,这可能有所帮助,但确实有一个重复调用GetEmails方法的紧密循环。您可以传入客户ID列表并立即获取。这需要in上的customerId声明。

答案 2 :(得分:1)

您可以获取此类列表客户的电子邮件地址

 public List<Email> GetEmails(List<int> listCustomerId)
    {
        var emailList = new List<Email>();
        var sql = "SELECT * FROM EmailsAddress WHERE Id IN (" + string.Join(",", listCustomerId) + ")";

        using ( var ObjectToAccessDatabaseAndStoreResultsIntoDataTable = new ObjectToObtainDbResultsIntoDataTable(_connection, sql))
        {
            foreach (DataRow row in  ObjectToAccessDatabaseAndStoreResultsIntoDataTable.Datatable)
            {
                var email = new Email
                {
                    MailAddress = Convert.ToString(row["MailAddress"]);
                    MailOwner = Convert.ToString(row["MailOwner"]);
                    MailSended = Convert.ToInt32(row["MailSended"]);
                    MailReceived = Convert.ToInt32(row["MailReceived"]);
                }

                emailList.Add(email);
            }

            return emailList;
        }
    }