【发布时间】: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