【问题标题】:SQL query times out when run from C#, fast in SQL Server Management Studio从 C# 运行时 SQL 查询超时,在 SQL Server Management Studio 中快速运行
【发布时间】:2015-06-05 05:18:43
【问题描述】:

我有一个使用下面列出的代码执行 SQL 查询的 C# 程序。我已经使用这段代码一段时间了,直到前几天都没有问题。

我正在向 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 只股票,但它不起作用(

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')

【问题讨论】:

  • 我们需要一个查询字符串的例子吗?可以是很多东西,可能需要索引、查询重写等......
  • 您需要在连接字符串中指定超时(足够长以完成您的查询)
  • _timeout 的值是多少?
  • 我真的怀疑一个有 900 个参数的查询是否在 1 秒内运行。缓存?
  • 您正在使用 AddWithValue,这需要 .net 为每个参数访问数据库以确定数据类型。当然,它可能会或可能不会获得正确的数据类型。 blogs.msmvps.com/jcoehoorn/blog/2014/05/12/…

标签: c# sql sql-server sql-server-2008 ado.net


【解决方案1】:

按优先顺序看三件事:

  1. Avoid using the AddWithValue() function,因为当 ADO.Net 猜测列类型错误时,这可能会产生灾难性的性能影响。做你必须能够为每个参数设置一个明确的数据库类型
  2. 查看OPTION RECOMPILE。
  3. 查看OPTIMIZE FOR UNKNOWN。只有在其他人失败后才这样做。

【讨论】:

  • 谢谢,我会试试这些。我还刚刚发现周四晚上有一些 Windows 更新应用到服务器(我在周五开始遇到问题),所以我们的 IT 人员正在调查这些。
  • Add 而不是 AddWithValue 没有帮助(尽管我做了那个改变)。并感谢优化未知信息的链接,这非常有帮助。我添加了该选项,它绝对解决了问题。谢谢!
【解决方案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. 其他人?

【讨论】:

  • 此外,您可以尝试在测试模式下在查询开始时使用SET SHOWPLAN_ALL ON; 查看执行计划。在工作查询和非工作查询中都以这种方式运行它,看看是否有任何明显的差异(这种格式有点难看,因为它返回一个您必须通过的信息表,与查询管理器不同,但它可能有助于找出不一致是什么)
猜你喜欢
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多