【发布时间】:2015-03-29 00:38:08
【问题描述】:
我有以下场景:一个最多包含 20000 个条目的表和另一个包含相应自定义字段的表。 我需要在所有列(包括自定义字段)上实现一个带有过滤机会的查询,并跳过并获取,并且我需要过滤后的总行数。 在动态 sql 的帮助下,我设法实现了一个查询,它将自定义字段作为列添加到第一个表中。 但是我真的很难实现运行非常快并且还返回总行数的skip and take功能。 由于并非我们所有的客户都在 SQL Server 2012 上运行,因此最好的方法是通过 row_number 上的 where 子句实现 take 和 skip,但我认为这也是最慢的选择。我喜欢 2012 案例的 OFFSET 和 FETCH 功能,但仍然获取行数似乎减慢了很多。
这是我从动态 sql 生成的查询,位于整个动态查询的下方,两者都有两个替代项作为 cmets
With tempTable AS
(
SELECT *
--1. ALTERNATIVE:
,ROW_NUMBER() Over (ORDER BY Nachname, Vorname desc) As ROW_NUMBER ,COUNT(1) OVER () as Total_Rows
FROM
(
SELECT [a].*, [DFSF].[Datenfeld_Name],[Datenfeld_Inhalt]
FROM
[dbo].[Ansprechpartner] AS a left join [dbo].[Datenfeld] AS dfe
ON [a].[Id] = [dfe].[Datenfeld_AnsprechpartnerID]
left join
[Datenfeld_Standardfelder] AS DFSF
ON dfe.[StandardfeldID] = [DFSF].[id] and datenfeld_kategorie = 'Ansprechpartner'
) AS j
PIVOT
(
max([Datenfeld_Inhalt]) FOR [j].[Datenfeld_Name] IN ([Medium],[Kontaktthema],[Mediengattung],[Medienthema],[E-Mail],[Homepage],[Rolle])
) AS p
)
SELECT *
--2. ALTERNATIVE:
--,COUNT(1) OVER ()
FROM tempTable
WHERE 1=1
-- 1. ALTERNATIVE:
and Row_Number BETWEEN 0 AND 100
ORDER BY Nachname, Vorname DESC
--2. ALTERNATIVE:
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
;
并跟踪整个动态查询。 我实际上认为,其中有一个错误,因为这样我不会得到正确的行数,我可能不得不在没有 row_number 过滤器的情况下再次调用它才能正确...
DECLARE @filterExpression nvarchar(MAX)
DECLARE @showOnlyDoublets int
DECLARE @sortExpression nvarchar(MAX)
DECLARE @skip AS int
DECLARE @take AS [int]
SELECT @skip = 0
SELECT @take = 100
--SELECT @filterExpression = 'WHERE Vorname like ''%luc%'''
SELECT @filterExpression = ' WHERE 1=1'
SELECT @sortExpression = 'ORDER BY Nachname, Vorname desc'
SELECT @showOnlyDoublets = 0
DECLARE @idList nvarchar(MAX)
select @idList = COALESCE(@idList + '],[', '[') + [DFSF].[Datenfeld_Name] from
[Datenfeld_Standardfelder] AS DFSF
where datenfeld_kategorie = 'Ansprechpartner'
SELECT @idList = @idList +']'
--SELECT @idList
DECLARE @sqlToRun nvarchar(max)
SET @sqlToRun =
'With tempTable As
(
SELECT *
, ROW_NUMBER() Over (' + @sortExpression + ') As Row_Number
FROM
(
SELECT [a].*, [DFSF].[Datenfeld_Name],[Datenfeld_Inhalt]--, CAST( ROW_NUMBER() OVER(ORDER BY [DFSF].[Datenfeld_Name] DESC) AS varchar(20))
FROM
[dbo].[Ansprechpartner] AS a left join [dbo].[Datenfeld] AS dfe
ON [a].[Id] = [dfe].[Datenfeld_AnsprechpartnerID]
left join
[Datenfeld_Standardfelder] AS DFSF
ON dfe.[StandardfeldID] = [DFSF].[id] and datenfeld_kategorie = ''Ansprechpartner''
) AS j
PIVOT
(
max([Datenfeld_Inhalt]) FOR [j].[Datenfeld_Name] IN (' + @idList + ')
) AS p
)
SELECT *, COUNT(*) OVER () as Total_Rows FROM tempTable
' + @filterExpression + '
AND Row_Number BETWEEN ' + CAST ( @skip AS varchar ) + ' AND ' + CAST ( @take AS varchar ) + '
' + @sortExpression + '
--OFFSET ' + CAST ( @skip AS varchar ) + ' ROWS FETCH NEXT ' + CAST ( @take AS varchar ) + ' ROWS ONLY
;'
PRINT @sqlToRun
EXECUTE sp_executesql @sqlToRun
所以我的问题是:有没有办法改进这个查询(两种选择之一)?还是您有完全不同的想法,因为我认为,无论哪种方式,如果我正确调用计数,都会花费很多时间。
【问题讨论】:
标签: sql-server performance count dynamic-sql skip-take