从C#运行的SQL查询超时,在SQL Server Management Studio中很快

14
我有一个C#程序,执行一个SQL查询,使用下面列出的代码。直到前几天,我一直使用这段代码没有问题。
我将一个包含一组字符串的查询字符串传递给SQL,这些字符串是股票标识符。几天前,我运行它时,查询超时了,如果让它继续运行,需要一小时以上的时间。我花了过去几天的时间来尝试调试它。在我的原始查询中,大约有900个标识符。
我尝试改变我能想到的一切,但得到了无法解释的结果。
例如:
1. 对于一个股票列表,查询可以工作,但对于另一个相同长度(根据字符串数和总长度)的列表则不行。 2. 它可以处理一个列表,但不能处理相同顺序的列表。 3. 对于一个列表,当恰好存在900个标识符时,它可以工作,但如果有899或901个标识符,则无法工作,而且我可以包括或排除不同的标识符并获得相同的结果,因此它不是由于其中一个标识符出现问题。
在每种情况下,我都捕获了程序传递的查询字符串,并将其复制到SQL Server Management Studio中,在每种情况下,查询在1秒内运行。
我已经阅读了关于这个问题的各种论坛和文献,以及有关在SQL Server Management Studio中工作但从程序运行时超时的查询的一切内容,但这似乎与其他情况不同,因为我可以找到失败的情况和类似的成功情况。
我希望能得到建议,了解可能发生了什么。
using (SqlConnection conn = new SqlConnection(_connectString))
{
    conn.Open();

    using (SqlCommand cmd = new SqlCommand(queryString, conn))
    {
        cmd.Parameters.Clear();
        cmd.CommandTimeout = _timeout;

        SqlParameter param;

        if (parms != null)
        {
            foreach (string parm in parms.Keys)
            {
                param = cmd.Parameters.AddWithValue(parm, parms[parm]);
            }
        }

        SqlDataReader reader = cmd.ExecuteReader();

        while (reader.Read())
        {
            QueryResult record = new QueryResult();
            record.Fields = new List<object>();

            for (int i = 0; i < returnColumns; ++i)
            {
                object value = reader.GetValue(i);

                if (value == DBNull.Value)
                    record.Fields.Add(null);
                else
                    record.Fields.Add(value);
            }

            result.Add(record);
        }

        reader.Close();
    }

    conn.Close();
}

这是我的查询。在这个版本中,我包含了65个股票,但它无法工作(小于等于64就可以工作)。

select
    distinct a.Cusip
,   d.Value_ / f.CumAdjFactor as split_adj_val

from qai.prc.PrcScChg a

join qai.dbo.SecMapX b
    on a.Code = b.venCode
    and b.VenType = 1
    and b.exchange = 1
    and b.Rank = (select Min(Rank) from qai.dbo.SecMapX where VenCode = a.Code and VenType = 1 and Exchange = 1)

join qai.dbo.SecMapX b2
    on b2.seccode = b.seccode
    and b2.ventype = 40
    and b2.exchange = 1
    and b2.Rank = (select Min(Rank) from qai.dbo.SecMapX where SecCode = b.SecCode and VenType = 40 and Exchange = 1)

join qai.dbo.SecMapX b3
    on b3.seccode = b.seccode
    and b3.ventype = 33
    and b3.exchange = 1
    and b3.Rank = (select Min(Rank) from qai.dbo.SecMapX where SecCode = b.SecCode and VenType = 33 and Exchange = 1)

join qai.dbo.DXLSecInfo c
    on b2.VenCode = c.Code

join qai.dbo.DXLAmData d
    on c.Code = d.Code
    and d.Date_ = @Date
    and d.Item = 6

left JOIN qai.dbo.DS2Adj f 
    ON f.InfoCode = b3.VenCode
    AND f.AdjType = 2
    and f.AdjDate <= @Date
    and ( f.EndAdjDate >= @Date or f.EndAdjDate is null )

where 
    a.cusip in ('00101J10', '00105510', '00120410', '00130H10', '00206R10',
    '00282410', '00287Y10', '00289620', '00724F10', '00817Y10', '00846U10',
    '00915810', '00936310', '00971T10', '01381710', '01535110', '01741R10',
    '01849010', '02000210', '02144110', '02209S10', '02313510', '02360810',
    '02553710', '02581610', '02687478', '03027X10', '03073E10', '03076C10',
    '03110010', '03116210', '03209510', '03251110', '03265410', '03741110',
    '03748R10', '03783310', '03822210', '03948310', '04621X10', '05276910',
    '05301510', '05329W10', '05333210', '05348410', '05361110', '05430310',
    '05493710', '05722410', '05849810', '06050510', '06405810', '06738310',
    '07181310', '07373010', '07588710', '07589610', '08143710', '08467070',
    '08651610', '09062X10', '09247X10', '09367110', '09702310', '09972410')

2
我们需要一个查询字符串的示例吗?可能有很多种情况,可能需要索引、查询重写等等... - Bruno
在连接字符串中,您需要指定超时时间(足够长以完成查询)。 - Yasir Majeed
_timeout 的值是多少? - UnhandledExcepSean
我真的很怀疑一个有900个参数的查询能在1秒内运行。缓存? - crthompson
我遇到了一个类似的问题,我注意到每当您使用带有命名参数(@parm)的查询字符串查询表格时,并且您正在查询的列没有索引,即使该列是VARCHAR并且具有索引..性能非常随机,不一致。使用存储过程应该会有所帮助。 - Prashant
显示剩余3条评论
2个回答

8

谢谢,我会尝试这些方法。我刚刚发现服务器在周四晚上进行了一些Windows更新(我在周五开始遇到问题),所以我们的IT人员正在调查这些更新。 - freckles
使用Add而不是AddWithValue并没有帮助(尽管我已经做出了这个更改)。感谢您提供的优化未知信息的链接,非常有帮助。我添加了该选项,它完全解决了问题。谢谢! - freckles

2
您还没有发布您的查询,但仅仅基于它是如何构建的动态参数列表和参数的数量,我猜想它可能与参数嗅探有关 - 请参见:

http://www.brentozar.com/archive/2013/06/the-elephant-and-the-mouse-or-parameter-sniffing-in-sql-server/

http://blogs.msdn.com/b/sqlprogrammability/archive/2008/11/26/optimize-for-unknown-a-little-known-sql-server-2008-feature.aspx

该问题的基本思想是为特定一组参数创建了一个最优查询执行计划,但对于另一组参数来说可能非常次优。
有几种方法可以解决参数嗅探问题(幸运的是,很多在 SQL Server 2008 中就已经出现):
1. 重构查询 2. 在存储过程中添加 "WITH RECOMPILE" / 在查询中添加 "OPTION (RECOMPILE)" 3. 在存储过程/查询中添加 "OPTIMIZE FOR UNKNOWN" / "OPTION (OPTIMIZE FOR...)" 4. 其他方法?

1
此外,您可以在测试模式下使用 SET SHOWPLAN_ALL ON; 在查询开头查看执行计划。在工作查询和非工作查询中都以这种方式运行,并查看是否有任何明显的差异(这种格式有点丑陋,因为它返回一个信息表格,您必须浏览,不像查询管理器那样,但它可能有助于找出不一致之处)。 - DarrenMB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接