0

我遇到了一个非常奇怪的问题:

我动态地形成 SQL 服务器命令,它的一部分是一组 LIKE 测试,用作对多个列和表的文本搜索。看起来像:

SET @text = '%' + REPLACE(REPLACE(REPLACE(@text, '!', '!!'), '%', '!%'), '_', '!_') + '%'

INSERT INTO
  @textFiltered
FROM
  @documents d 
  LEFT JOIN docData t1 WITH (NOLOCK)
    ON t1.ID = d.ID AND
       (t1.Topic like @text escape '!'
        OR t1.Subject like @text escape '!')
  LEFT JOIN docData2 t2 WITH (NOLOCK)
    ON t2.ID = d.ID AND 
       t2.Name like @text escape '!'
WHERE
  t1.ID IS NOT NULL 
  OR t2.ID IS NOT NULL

(当然,这不是进行文本搜索的最佳方式,但这不是重点)

现在,当我在 C# 中创建 SQLCommand 时,如下所示:

using (var cmd = new SqlCommand())
{
   cmd.CommandText = cmdText;
   cmd.CommandType = CommandType.Text;
   cmd.Connection = connection;
   cmd.Parameters.Add("text", NVarChar, 4000).Value = searchText;
   var reader = cmd.ExecuteReader();
   ....
}

执行的性能很差(比如 8 秒),而在 SQL Management Studio 中执行相同的查询要快得多(比如 500 毫秒)。但是,如果不是将文本作为参数传递,我将其嵌入到 SQL 文本中:

DECLARE @text nvarchar(max)
SET @text = '<embedded-text>'

然后 SqlCommand 也运行得很快。更奇怪的是,这种行为似乎与 LIKE 子句中使用的一组列相关(不知道如何)。这些列的类型可以是 nvarchar(size)、nvarchar(max)、ntext。

我怀疑问题出在参数上-也许它的类型不正确或其他。

PS 试图创建大小 = 搜索文本长度 + 1 的参数 - 没有帮助。

4

1 回答 1

0

我最好的猜测是它与 SQL Server 为您选择的查询计划有关。使用 SQL 服务器可以根据现有统计信息评估的常量 varchar 与使用服务器一无所知的任意变量之间存在很大差异。

您可以尝试 OPTION (RECOMPILE) 提示。尽管此提示将导致在每次调用时编译存储过程,但它还允许 SQL Server 搜索给定值的最佳计划,也许在您的情况下这将是一个很好的权衡。

您还可以为存储过程的两个选项添加查询计划,也许有人将能够看到差异,并指出确切的问题。

于 2013-03-04T15:51:11.873 回答