【问题标题】:How can i pass parameters to a Common Table Expression inside a sp?如何将参数传递给 sp 内的公用表表达式?
【发布时间】:2016-02-03 16:00:34
【问题描述】:

我想使用 CTE(公用表表达式)重写一个正常运行但速度较慢的存储过程

我有一个大的存储过程,我根据使用的参数动态构建必要的 SQL。目前有 27 个参数,我编写的 SQL 字符串最后执行如下:

    DECLARE @SqlWhereClause NVARCHAR(MAX)  
SET @SqlWhereClause = ' WHERE ([InTimeStamp] BETWEEN ''' + CONVERT(VARCHAR(19), @fromDate, 120) + ''' AND ''' + CONVERT(VARCHAR(19), @toDate, 120) + ''')'

IF @showOnlyErrors = '1'  
   BEGIN
     SET @SqlWhereClause += ' AND Status = ''Error'''  
    END

IF LEN(LTRIM(RTRIM(@docNo))) > 0  
  BEGIN  
    IF @matchExact = '1'   
      BEGIN
         SET @SqlWhereClause += ' AND DocumentNumber = ''' + @docNo + ''''  
      END
   ELSE
    BEGIN   
        SET @SqlWhereClause += ' AND (contains([DocumentNumber],'''+ @docNo +'''))'
    END 
  END     

最后,我添加了分页并将其转换为最终的形式SQL:

    IF CONVERT(int, LTRIM(RTRIM(@takeRows))) > 0   
   BEGIN
     SET @SqlOrderByClause += ' OFFSET ' + @rowNumberToSkip +' ROWS FETCH NEXT '+ @takeRows +' ROWS ONLY '
     Set @RowCount = ' Select @totalRecords = count(1) from  dbo.Messages WITH (NOLOCK) ' + @SqlWhereClause
   END

    SET @SQL = @SqlSelect + @SqlFrom + @SqlWhereClause + @SqlOrderByClause + ' ; '  + @RowCount  
    PRINT @SQL  
    EXECUTE sp_executesql @SQL, @params, @totalRecords OUTPUT 

一切都像魅力一样运作。没问题。只有性能问题。为了解决其中一个问题,我会尝试使用 CTE(公用表表达式)

但这不起作用:

   With DataSQL AS
    (@SqlSelect + @SqlFrom + @SqlWhereClause + @SqlOrderByClause),

   - incorrect syntax near @SqlSelect - Expecting '(' or Select.

我也试过这个:

     WITH DataSQL AS 
     ( Select @SqlSelect    From @SqlFromFast   
    Where @SqlWhereClause   Order By @SqlOrderByClause),

我明白了:

    An expression of non-boolean type specified in a context where a condition is expected, near 'Order'

有什么想法吗?还是不能将 CTE 与多个变量一起使用?到目前为止,我发现的只是带有一个甚至两个变量的查询。

【问题讨论】:

  • 什么是慢?构建动态sql还是执行动态sql?
  • 执行需要很长时间。还因为行数几乎与查询本身一样多。我在执行计划里查了一下,有50%/50%
  • 你看执行计划了吗? SSMS 是否建议任何索引?
  • 索引的问题在于,一方面我们有许多包含(Like)搜索,而索引没有帮助,另一方面有更常用的典型 12-15 搜索条件从总共27个。而且其他的也在使用中。该表已经是一个聚合表,仅用于监控目的,因此不存在更新,插入是通过批处理完成的(每 5 分钟一次),删除是通过作业完成的(删除所有超过 52 周的时间)。

标签: tsql stored-procedures common-table-expression


【解决方案1】:

你可以试试:

WITH DataSQL AS
(
     SELECT   @SqlSelect SqlSelect
     ,        @SqlFromFast SqlFromFast
     ,        etcetera
)

确保您提供别名,否则将不起作用。我怀疑它会帮助您解决性能问题。您可以尝试使用临时表,这通常会更快。你也可以尝试使用内部变量:

DECLARE @Select VARCHAR(MAX) = @SQLSelect 

改用这些可能会对优化器有所帮助,但这取决于您的数据。

【讨论】:

  • 目前我检测到的最大瓶颈是@RowCount 的第二个查询。它与查询本身花费的时间大致相同。
  • 变量 SqlSelect 包含多个列,与 SqlWhereClause 变量相同。 SET @SqlSelect = ' [RecordId], [TransactionId], [Status], [InTimeStamp], [OutTimeStamp], [Doctype], [DocumentNumber], [DocFormat], .....
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-09
  • 1970-01-01
  • 2014-01-10
  • 1970-01-01
  • 2011-06-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多