我有以下场景:一个最多包含 20000 个条目的表和另一个具有相应自定义字段的表。我需要在所有列(包括自定义字段)上实现一个带有过滤机会的查询,并跳过并获取,并且我需要过滤后的总行数。在动态 sql 的帮助下,我设法实现了一个查询,它将自定义字段作为列添加到第一个表中。但是我真的很难实现运行非常快并且还返回总行数的skip and take功能。由于并非我们所有的客户都在 SQL Server 2012 上运行,因此最好的方法是通过 row_number 上的 where 子句实现 take 和 skip,但我认为这也是最慢的选择。我喜欢 2012 案例的 OFFSET 和 FETCH 功能,
这是我从动态 sql 得到的查询,在整个动态查询下方,都有两个备选方案作为注释
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
所以我的问题是:有没有办法改进这个查询(两种选择之一)?还是您有完全不同的想法,因为我认为,无论哪种方式,如果我正确地调用计数,都会花费很多时间。