添加 SELECT COUNT(*) 子条款会破坏 SQL 服务器中的性能

Adding SELECT COUNT(*) subclause trashes performance in SQL Server

我正在构建一个查询,最新的步骤涉及添加一个 SELECT COUNT(*) FROM [modification] 子句以允许我检测查询的最后一行,但这会破坏性能:

SELECT CONCAT(
      IIF(row_number() OVER (ORDER BY forecastId) % 50000 = 1,
          CONCAT('INSERT INTO modification (userId, epochTime, ',
                 'forecastId, description, auxText, auxDate) VALUES ('), 
          '    ('),
      userId, ',',
      epochTime, ',',
      forecastId, ',',
      '''', dbo.encode4MySql(description), ''',',
      '''', dbo.encode4MySql(auxText), ''',',
      '''', CONVERT(VARCHAR(20), auxDate, 120), ''')',
      IIF(row_number() OVER (ORDER BY forecastId) % 50000 = 0
          OR row_number() OVER (ORDER BY forecastId) = 
                      (SELECT COUNT(*) FROM modification),
          '; COMMIT;', ','))
FROM modification
ORDER BY forecastId;

如果您看不到我在做什么,我正在构建 INSERT () VALUES (),(),(),... 一次 50000 行的语句。

请限制对评论的完全替代方法的建议。我正在寻找一种方法来找到最后一行号,而不会大幅降低查询速度 - 它确实如此。

我不太熟悉查询计划,但如果有帮助,可以 post 了解一下。我已经从相关问题中尝试了很多东西,但我无法开始工作。

你的表达式比较复杂,所以SQL服务器可能没有优化它。将逻辑移至 FROM 子句:

FROM (SELECT m.*, COUNT(*) OVER () as num_rows
      FROM modification m
     ) m

然后在查询的其余部分使用 num_rows

假设您不想更改当前设计,您可以在最后添加一个额外的 UNION ALL 步骤。通过查看您的查询,更改查询的唯一目的似乎是在末尾添加一个 COMMIT。

CURRENT QUERY
UNION ALL
SELECT 'COMMIT;';

让我知道这是否适合你。

***********更新*********

我认为这个查询更容易解决问题。看看它是否会表现得更好。您必须为 table.

插入 CTE 部分
SELECT BusinessEntityID,JobTitle,HireDate INTO dbo.TestTable FROM [HumanResources].[Employee]
SELECT TOP 0 BusinessEntityID,JobTitle,HireDate INTO dbo.TestTable2 FROM [HumanResources].[Employee]

SET NOCOUNT ON


WITH CTE AS (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) Col, 
    ' (' + 
    CAST(BusinessEntityID AS VARCHAR(20)) + 
    ', ''' + 
    JobTitle + 
    ''', ''' + 
    CONVERT(VARCHAR(20), HireDate, 120) +
    ''')' Query
FROM TestTable
) 
    SELECT 
        CASE 
        WHEN COL % 50 = 0 THEN ', ' + Query + ' COMMIT;' 
        WHEN COL % 50 = 1 THEN ' INSERT INTO dbo.TestTable2 (BusinessEntityID, JobTitle, HireDate) VALUES ' + Query
        ELSE ', ' + Query 
        END 
    FROM CTE
UNION ALL SELECT 'COMMIT;'

另一种选择是 order by forecastId desc 在最后 or:

IIF(row_number() OVER (ORDER BY forecastId) % 50000 = 0
          OR row_number() OVER (ORDER BY forecastId desc) = 1,
          '; COMMIT;', ','))