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

问题描述 投票:0回答:3

我有一个使用下面列出的代码执行 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 只股票,但它不起作用 (<=64 does work).

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')
c# sql sql-server sql-server-2008 ado.net
3个回答
8
投票

需要注意的三件事(按优先顺序排列):

  1. 避免使用
    AddWithValue()
    函数
    ,因为当 ADO.Net 猜测列类型错误时,这可能会产生灾难性的性能影响。执行您必须执行的操作才能为每个参数设置显式数据库类型
  2. 查看选项重新编译
  3. 查看针对未知进行优化。仅在其他方法失败后才执行此操作。

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. 其他?

0
投票

就我而言,问题是结果集中的列值包含二进制格式的图像,删除特定列后,ssms 和 ado.net 执行该过程所花费的时间开始匹配。

© www.soinside.com 2019 - 2024. All rights reserved.