【问题标题】:Connection timeout on query on large table大表查询连接超时
【发布时间】:2011-05-17 23:21:23
【问题描述】:

我在从大表上的查询中提取数据时遇到脚本超时问题。

该表有 9,521,457 行。

我要执行的查询是:

SELECT * 
FROM `dialhistory` 
WHERE `customerId` IN (22606536, 22707251, 41598836);

此查询在 HeidiSQL 上运行没有问题,大约需要 171 秒并返回 434 行。

但是当我运行我的 C# 脚本时,它会在 161 行后超时。

16:54:55: Row 1
...
16:54:55: Row 161
16:55:32: Error -> Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.

这里是代码

public MySqlDatabase(string server, string database, string username, string password)
{
    ConnectionString = "SERVER=" + server + ";DATABASE=" + database + ";UID=" + username + ";PASSWORD=" + password + ";";

}

public IQueryable<DailHistory> GetHistory(IList<int> customerIds)
{
    IList<DailHistory> list = new List<DailHistory>();
    var connection = new MySqlConnection(ConnectionString);
    connection.Open();
    var command = connection.CreateCommand();
    command.CommandText = "SELECT * FROM `dialhistory` WHERE `customerId` in ("+string.Join(",", customerIds.ToArray())+")";
    var reader = command.ExecuteReader();
    int i = 1;
    while (reader.Read())
    {
        Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Row " + i);
        i++;
        try
        {
            var d = new DailHistory();
            d.CustomerId = int.Parse((string) reader["customerId"]);
            d.Agent = ParseNullAbleString(reader["agent"].ToString());
            d.CallBackReason = ParseNullAbleString(reader["callBackReason"].ToString());
            d.CallState = ParseCallSate(reader["callState"].ToString());
            d.ContactResponse = ParseNullAbleString(reader["contactResponse"].ToString());
            d.DailTime = new DailTime(reader["dialStart"].ToString(), reader["dialEnd"].ToString());
            d.HistoryIndex = int.Parse(reader["historyIndex"].ToString());
            d.Note = ParseNullAbleString(reader["note"].ToString());
            d.OldDialNo = ParseNullAbleInt(reader["oldDialNo"].ToString());
            d.ProjectJob = ParseNullAbleString(reader["projectJob"].ToString());
            list.Add(d);
        }
        catch(Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
    reader.Close();
    return list.AsQueryable();
}

【问题讨论】:

    标签: c# mysql timeout


    【解决方案1】:
    command.CommandTimeout = 2147483;
    

    MySQL 命令超时的最大值是 32 位整数的最大值,以毫秒为单位,2147483647。但在 C# 中,CommandTimeout 属性以秒为单位,而不是毫秒,因此任何高于 2147483 的值都会导致异常。

    虽然这不是无限的,但它是 24 天 20 小时 31 分 23 秒,希望能满足您的需求。

    将值设置为 0 对我不起作用。 CommandTimeout 属性不会保留 0 的值,而是会自动更改回 30。

    将值设置为 -1 似乎确实有效,但我没有对其进行足够的测试以确保永远不会发生超时。

    最安全的选择:选择 2147483。

    【讨论】:

      【解决方案2】:
      command.CommandTimeout = int.MaxValue;
      

      如果您更确切地知道要插入哪个数字,请执行此操作。如果您将其设置为 int.MaxValue,则您正在消除安全屏障。

      【讨论】:

        【解决方案3】:

        customerId 列上添加索引。

        【讨论】:

        • 有,是主键!
        • @DoomStone - 我不明白它怎么可能需要 171 秒才能返回 434 行。您是否返回了一些非常宽的数据(例如 BLOB)并且如果 3 个客户 ID 返回 434 行,CustomerId 本身就不能成为 PK。索引中的其他列是什么?这些列在复合索引中的顺序是什么?
        • 您的意思是这是另一个表的主键吗?如果它是该表的主键,那么您的查询不应返回 434 行。
        【解决方案4】:

        在命令对象上设置CommandTimeout

        var command = connection.CreateCommand();
        command.CommandTimeout = 0;
        //zero specifies never timeout. 
        //Any number greater than zero is the number of seconds before 
        //the command will time out.
        

        【讨论】:

        • command.CommandTimeout = 0;没有工作:(它仍然超时
        • @DoomStone 您的数据库可以定义超时,当您使用 commandTimeout 请求超时时,这可以被数据库配置覆盖。在我的情况下,它对我有用,但在你的情况下,这可能是你需要与你的 DBA 一起解决的问题。(对于未来的读者......显然你的问题是多年前的抱歉)
        猜你喜欢
        • 2010-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-26
        • 2012-08-01
        • 2013-02-07
        相关资源
        最近更新 更多