添加SELECT COUNT(*)子句会破坏SQL Server中的性能

时间:2017-09-09 17:52:23

标签: sql sql-server multiple-insert

我正在构建查询,最新一步涉及添加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;

如果您无法看到我正在做的事情,我一次只能构建50000行的INSERT () VALUES (),(),(),...语句。

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

我并不熟悉查询计划,但如果有帮助,可以在此发帖。我在这里尝试过很多关于相关问题的事情,但是没有什么我可以开始工作的。

3 个答案:

答案 0 :(得分:1)

您有一个相当复杂的表达式,因此SQL Server可能无法对其进行优化。将逻辑移动到FROM子句:

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

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

答案 1 :(得分:1)

另一个选项是最终order by forecastId desc中的or

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

答案 2 :(得分:0)

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

CURRENT QUERY
UNION ALL
SELECT 'COMMIT;';

请告诉我这是否适合您。

*********** UPDATE *********

我认为此查询更容易排除故障。看看它是否会更好。你必须为你的桌子插入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;'