【问题标题】:Slow SQLDataReader GetString慢 SQLDataReader GetString
【发布时间】:2014-12-31 21:50:28
【问题描述】:

一行 rdr.GetString 需要 12-15 秒

几行需要 4 - 5 秒
几个需要 1-4 秒
大多数行都小于 100 毫秒

整个查询仅返回 3286 行,在 SSMS 中运行时间为 15 秒

[Value] 是 varchar(600) - 据我所知没有什么特别之处
[fieldID]、[value] 上有一个索引被重建(多次)

在 SqlDataReader 中读取第 208 行需要 12 - 15 秒
读取这一行所花费的时间与读取所有剩余的 3,285 行所花费的时间一样

如果我将 [fieldID] 上的排序更改为 desc,那么它会挂在第 2050 行
那不是同一行(甚至不是相同的[fieldID])

在 rdr.GetString 之前是一个 rdr.GetByte,它永远不会挂在 GetByte 上。 它已经有行了! 即使用类似但不精确的数据库访问另一台服务器,它也会挂起。

我知道这听起来很疯狂,但它正在发生。 感觉就像 SqlDataReader 挂了,但我一直在这个应用程序中使用 SqlDataReader 并返回比这更多的行。

如果我在 fieldID 更改时执行手动 GC.Collect(),它仍然会挂在几乎相同的行上。 个别挂起的次数要少一些,但总数大致相同。使用 1 秒的阈值可能会有一个刚刚进入或刚刚退出的阈值,但问题行肯定会重复。

认为这可能与挂起之间的字符数有关,但可以低至 600 和高达 60,000。

但它似乎与返回的数据有关。 如果我排除或包含 [rownumber] (并且不阅读它),它将挂在不同的行上。 但是这些行在同一附近。

 fieldID = rdr.GetByte(0);    // this line does not hang
 delta = sw.ElapsedMilliseconds;
 textValue = rdr.GetString(1);  // this is the line that hang on some rows 
 if ((sw.ElapsedMilliseconds - delta) > 1000L)
    Debug.WriteLine("GabeLib_Helper sw in  fields  thisFieldID = " + thisFieldID + " counter = " + counter + " ccount = " + ccount + " after getstring read delta = " + (sw.ElapsedMilliseconds - delta).ToString("N0") + " textValue = " + textValue);

select [fieldID], [value], [rowNum]
from 
(
SELECT [fieldID], ltrim(rtrim([value])) as [value]
     , ROW_NUMBER() over ( partition by [fieldID] order by ltrim(rtrim([value])) ) as [rowNum]
  FROM [docSVtext] with (nolock)
  JOIN [docFieldDef] with (nolock)
    ON [docFieldDef].[ID] = [fieldID] 
   AND [docFieldDef].[typeID] in (101) 
   AND [docFieldDef].[active] =  'true' 
   AND len(ltrim(rtrim([value]))) > 0 and len(ltrim(rtrim([value]))) <= 200 
  JOIN [docSVsys] with (nolock) 
    on [docSVsys].[sID] = [docSVtext].[sID] 
   and [docSVsys].[visibility] = 0 
 group by [fieldID], ltrim(rtrim([value]))
 ) as withRow
 where [rowNum] < 1001
 order by [fieldID], [rowNum]

如果我添加 rdr.GetInt64(2);以上 rdr.GetString(1);
然后它挂在 rdr.GetInt64(2);并且不会挂在 rdr.GetString(1);
并使用 rdr.GetInt64(2);我得到了一个缓慢的 rdr.Read()。

delta = sw.ElapsedMilliseconds; 
rowNum = rdr.GetInt64(2);
if ((sw.ElapsedMilliseconds - delta) > 1000L)
    Debug.WriteLine("GabeLib_Helper sw in  fields  in PastEntries new rowNum  rdr.GetInt64(2) " + rowNum + " counter = " + counter + " ccount = " + ccount + "  delta = " + (sw.ElapsedMilliseconds - delta).ToString("N0"));

下面的查询在 SSMS 中运行 2 秒
这不是问题查询
包含以显示索引似乎正在工作

  select fieldID, value, count(*)  
  from docSVtext 
  group by fieldID, value

我跟踪了 GC,它与减速无关
即使 GC 运行也只需要 20 毫秒

delta = sw.ElapsedMilliseconds;
List<int> gcCounts = new List<int>();
for (int g = 0; g <= GC.MaxGeneration; g++) gcCounts.Add(GC.CollectionCount(g));
textValue = rdr.GetString(1);  //  " Chen, Andy </O=ENRON/OU=NA/CN=RECIPIENTS/CN=ACHEN>" + Guid.NewGuid(); //
if ((sw.ElapsedMilliseconds - delta) > 100L)
{
    Debug.WriteLine("GabeLib_Helper sw in  fields  thisFieldID = " + thisFieldID + " counter = " + counter + " ccount = " + ccount + " after getstring read delta = " + (sw.ElapsedMilliseconds - delta).ToString("N0") + " textValue = " + textValue);

}
for (int g = 0; g <= GC.MaxGeneration; g++)
{
    if (GC.CollectionCount(g) != gcCounts[g])
        Debug.WriteLine("GabeLib_Helper GC new count = " + GC.CollectionCount(g) + " old count =" + gcCounts[g] + " generation " + g + " ccount = " + ccount + " after getstring read delta = " + (sw.ElapsedMilliseconds - delta).ToString("N0"));
}

【问题讨论】:

  • @Rhumborl 但它挂在 GetString 上——这怎么用词不当?如果我将 textValue 分配给硬编码的“值”,这没有问题
  • 第一个查询是导致问题的原因吗?即order by fieldID, rownumdesc 添加到它?如果是这样,请尝试在子查询的order by 子句中删除“ltrim(rtrim(..))”。
  • @shahkalpesh 没有解决问题。它现在挂在不同的行上。正如我所说,查询在 SSMS 中运行良好。它已经在该行上执行了 rdr.GetByte(0) 没有问题。

标签: .net sqldatareader


【解决方案1】:

我想我明白了

如果我删除了

where [rowNum] < 1001

然后是没有任何长行读取
该查询需要更长的时间,因为它现在读取每一行
那个挂起是当它跳过那些行时
由于实际的读者在阅读之前很难看到

但是SSMS中没有问题仍然让我感到困惑

试过了

select ID, count(*) 
  from table 
  ...
group by ID 
having count(*) > x

仅查询 x 计数下的 ID
问题是查询需要几秒钟才能运行

我最终做的是

select top (x + 1), value 
  from table 
 where ID = i1
 group by value;
select top (x + 1), value 
  from table 
 where ID = i2
 group by value;
...

如果计数达到 x + 1,那么我不使用它

发生的事情是一些非常重要的事情,占用了很多时间,而我什至不想要这些。即使得到一个大计数也是昂贵的

【讨论】:

    猜你喜欢
    • 2010-10-14
    • 2021-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多