有没有办法加快阅读数据?

时间:2012-06-11 16:30:47

标签: .net postgresql sqldatareader npgsql data-retrieval

在程序中,我创建了以下逻辑,用于从数据库中读取数据并将其存储到List<>中:

                NpgsqlCommand cmd = new NpgsqlCommand(query, conn);
                List<UserInfo> result = new List<UserInfo>();
                Npgsql.NpgsqlDataReader rdr = cmd.ExecuteReader();
                while (rdr.Read())
                {
                    string userId = rdr[0].ToString();
                    string sex = rdr[1].ToString();
                    string strDateBirth = rdr[2].ToString();
                    string zip = rdr[3].ToString();

                    UserInfo userInfo = new UserInfo();
                    userInfo.Msisdn = userId;
                    userInfo.Gender = sex;
                    try
                    {
                        userInfo.BirthDate = Convert.ToDateTime(strDateBirth);
                    }
                    catch (Exception ex)
                    {
                    }
                    userInfo.ZipCode = zip;
                    userInfo.DemographicsKnown = true;
                    userInfo.AgeGroup = getAgeGroup(strDateBirth);
                    if (result.Count(x => x.Id== userId) == 0)
                        result.Add(userInfo);
                }

此代码的性能非常差。有超过2M的记录,半小时后,userInfo列表只包含300.000条记录。

有谁知道如何加速从数据库中读取数据?

3 个答案:

答案 0 :(得分:3)

当你的意思是.Count时,你正在使用.Any() 每当你打电话给.Count时,你都在枚举整个集合,看看你是否只有一场比赛....

考虑你问的问题:
“你有多少行匹配这个条件?这个数字是否等于零?”

你真正的意思是:
“任何行都符合这个条件吗?”

在该上下文中,您可以创建userId值的Hashset。检查Hashset(或字典)中是否存在比检查列表中的相同要快得多。

此外,如果您执行已经拥有userId,那么您无缘无故地解析并读取所有值。首先检查myHashset.Contains(userId),然后添加。

这是它缓慢的主要原因。对于n行,您正在执行集合的第n个三角形枚举!

编辑:考虑这个未经测试的更改:我不知道您的读者是否支持类似GetString()的类型读取方法,所以如果不支持,那么只需使用之前的内容。< / p>

NpgsqlCommand cmd = new NpgsqlCommand(query, conn);
List<UserInfo> result = new List<UserInfo>();
Npgsql.NpgsqlDataReader rdr = cmd.ExecuteReader();
HashSet<string> userHash = new HashSet<string>(); // is this actually an int?

while (rdr.Read())
{
    string userId = rdr.GetString(0);
    If (!userHash.Contains(userId))
    {
        string strDateBirth = rdrGetString(2);
        UserInfo userInfo = new UserInfo();
        userInfo.Msisdn = userId;
        userInfo.Gender = rdr.GetString(1);
        datetime parseddate; // this is not used if the parse fails
        if (Datetime.TryParse(strDateBirth, out parseddate))
        {
            userInfo.BirthDate = parseddate;
            // userInfo.AgeGroup = getAgeGroup(strDateBirth); // why take the string?
            // rewrite your getAgeGroup method to take the datetime
            userInfo.AgeGroup = getAgeGroup(parseddate);
        }
        userInfo.ZipCode = rdr.GetString(3);
        userInfo.DemographicsKnown = true;
        result.Add(userInfo);
        userHash.Add(userId);
    }
}

这将始终保留您找到的用户行的第一个实例(这是您当前代码所执行的操作)。如果您想保留最后实例,则可以使用字典并完全取消.Contains()调用。

编辑:我刚注意到我的示例从未将用户ID添加到哈希...哎呀......将其添加到其中。

答案 1 :(得分:2)

所有这些execption处理都会使你的程序变慢。例外情况适用于 特殊情况 如果您的代码丢失了超过10个执行程序,则需要重新考虑您的设计。

而不是每次出现格式错误的日期时都使用DateTime.TryParse(string, DateTime)代替执行。它会加速你的代码。

////Replace This
//try
//{
//    userInfo.BirthDate = Convert.ToDateTime(strDateBirth);
//}
//catch (Exception ex)
//{
//}

//With this
DateTime bithDate;
if(DateTime.TryParse(strDateBirth, out bithDate)
{
    userInfo.BirthDate = bithDate;
}

rdr[2]列的数据类型是什么?它已经是DateTime吗?另一件事是停止在任何地方的对象上调用ToString并使用正确的方法。

while(rdr.Read())
{
    UserInfo userInfo = new UserInfo();
    userInfo.Msisdn = rdr.GetString(0);
    userInfo.Gender = rdr.GetString(1);

    DateTime? birthdate = null; //This is a nullable DateTime see http://msdn.microsoft.com/en-us/library/b3h38hb0.aspx

    if(rdr.IsDbNull() == false)
    {
        birthdate = rdr.GetDateTime(2);
        userInfo.BirthDate = birthdate.Value;
    }
    userInfo.ZipCode = rdr.GetString(3);
    userInfo.DemographicsKnown = true;
    userInfo.AgeGroup = getAgeGroup(birthdate); //You may need to edit getAgeGroup to take in a nullable DateTime

    if (result.Any(x => x.Id== userId)) //Any is much faster than count for your check, see Matthew PK's answer.
        result.Add(userInfo);
}

答案 2 :(得分:0)

为了加快从数据库中获取数据的速度,您可能需要考虑不同的数据读取方式,而不是通过读取器循环。

DataSet my_dataset = new DataSet();
NpgsqlDataAdapter my_dataadapter = default(NpgsqlDataAdapter);

NpgsqlCommand cmd = new NpgsqlCommand(query, conn);
my_dataadapter = new NpgsqlDataAdapter(cmd);
my_dataadapter.Fill(my_dataset, "mydataset");

然后对数据集做任何事情。
你可能对速度的差异感到非常惊讶。